AngularJS - atrybut wartości na wejściowym polu tekstowym jest ignorowany, gdy używany jest model ng?

218

Używam AngularJS, jeśli ustawiam wartość prostego pola tekstowego na coś takiego jak „bob” poniżej. Wartość nie wyświetla się, jeśli ng-modelatrybut zostanie dodany.

    <input type="text"
           id="rootFolder"
           ng-model="rootFolders"
           disabled="disabled"
           value="Bob"
           size="40"/>

Ktoś wie o prostym obejściu, aby ustawić domyślne dane wejściowe na coś i zachować ng-model? Próbowałem użyć ng-bindwartości domyślnej, ale to też nie działa.

Witaj świecie
źródło

Odpowiedzi:

223

To pożądane zachowanie, powinieneś zdefiniować model w kontrolerze, a nie w widoku.

<div ng-controller="Main">
  <input type="text" ng-model="rootFolders">
</div>


function Main($scope) {
  $scope.rootFolders = 'bob';
}
Vojta
źródło
11
Dzięki. Ale w tym przypadku model jest ustawiony w kontrolerze. A w dokumentach Angulara zawsze jest tak samo, dane są ustawiane w kontrolerze. Ale mój kontroler jest w pliku JS. Jak to zrobić w formularzu „edycji”? Jak przekazać domyślne dane formularza do kontrolera „drogą kątową”?
ByScripts
8
Dla mnie to nie działa, ale dodanie dodatkowego atrybutu ng-init pokazanego przez Marka Rajcoka (ng-init = "rootFolders = 'Bob'") działa dobrze.
Kaizar Laxmidhar
A jak ustawić wartość domyślną, jeśli mam pole wejściowe, takie jak: <input type = "number" ng-model = "newTransaction [$ index] [user.email]" />?
shish
188

Vojta opisał „Angular way”, ale jeśli naprawdę musisz to zrobić, @urbanek niedawno opublikował obejście za pomocą ng-init:

<input type="text" ng-model="rootFolders" ng-init="rootFolders='Bob'" value="Bob">

https://groups.google.com/d/msg/angular/Hn3eztNHFXw/wk3HyOl9fhcJ

Mark Rajcok
źródło
33
Możesz nie potrzebować części „wartość =„ Bob ”.
Mark Rajcok,
2
+1, ale, jak wspomniano w jednym z postów w połączonej dyskusji, należy tego unikać (ponieważ logicznie jest to mniej poprawne i utrudnia testowanie).
0xc0de
1
Ta metoda działa dobrze, jeśli używasz wartości modelu również w wersji 1.2. <... ng-init = "rootFolders = someModelAttribute" ...>
dmcqu314
@MarkRajcok, masz tak wiele świetnych wpisów AngularJS na Stack Overflow! Dziękujemy za cały czas poświęcony na dzielenie się spostrzeżeniami ze społecznością SO. Jestem pewien, że mówię w imieniu wielu zwolnionych programistów, gdy mówię, że szczerze doceniamy wszystkie godziny, które nam uratowałeś!
Jeremy Moritz
1
Naprawdę doceniam odpowiedź Marka, ponieważ to rozwiązało mój problem. Potwierdzam, że NIE potrzebujemy value="Bob"udziału w tagu wejściowym.
Devner,
68

Wydaje się, że przesłanianie dyrektywy wejściowej wykonuje zadanie. Wprowadziłem kilka drobnych zmian w kodzie Dana Hunsakera :

  • Dodano sprawdzenie ngModel przed próbą użycia $parse().assign()na polach bez atrybutów ngModel.
  • Poprawiono assign()kolejność paramów funkcji.
app.directive('input', function ($parse) {
  return {
    restrict: 'E',
    require: '?ngModel',
    link: function (scope, element, attrs) {
      if (attrs.ngModel && attrs.value) {
        $parse(attrs.ngModel).assign(scope, attrs.value);
      }
    }
  };
});
Ivan Breet
źródło
To najlepsza odpowiedź, jaką znalazłem! ... rozwiązuje mój problem w elegancki sposób. Musiałem uchwycić wartość na ukrytym wejściu (token formularza Symfony, wygenerowany na serwerze).
PachinSV
To nie tylko sprytne, ale najlepsze rozwiązanie. W moim przypadku nie mogę ustawić domyślnej wartości ng-modelu na kontrolerze, ponieważ jest to formularz PHP, jeśli sprawdzanie poprawności po stronie serwera się nie powiedzie, formularz zostanie odświeżony i cokolwiek w modelu ng zostanie utracone, usuwając wartość wejściową też.
Luis Elizondo
2
Wydaje się to najlepszym rozwiązaniem, jeśli chcesz, aby podstawowa wersja formularza HTML działała bez JavaScript.
Darren
Doskonałe rozwiązanie, które naprawdę powinno być domyślną konfigurowalną opcją samego kąta.
Gracie
Dzięki za twoje rozwiązanie. Jak rozwiązałbyś problem z wprowadzaniem liczb? Zgłasza
mate.gwozdz
21

Angular way

Prawidłowym sposobem Angulara jest napisanie jednej strony aplikacji AJAX w szablonie formularza, a następnie wypełnienie jej dynamicznie z modelu. Model nie jest domyślnie wypełniany z formularza, ponieważ jest jedynym źródłem prawdy. Zamiast tego Angular pójdzie w drugą stronę i spróbuje wypełnić formularz z modelu.

Jeśli jednak nie masz czasu, aby zacząć od nowa

Jeśli masz napisaną aplikację, może to wymagać dość dużych zmian architektonicznych. Jeśli próbujesz użyć Angulara do ulepszenia istniejącego formularza, zamiast budować od podstaw całą aplikację na jednej stronie, możesz pobrać wartość z formularza i zapisać ją w zakresie w czasie łączenia za pomocą dyrektywy. Angular następnie powiąże wartość w zakresie z powrotem do formularza i utrzyma ją w synchronizacji.

Korzystanie z dyrektywy

Możesz użyć stosunkowo prostej dyrektywy, aby pobrać wartość z formularza i załadować ją do bieżącego zakresu. Tutaj zdefiniowałem dyrektywę initFromForm.

var myApp = angular.module("myApp", ['initFromForm']);

angular.module('initFromForm', [])
  .directive("initFromForm", function ($parse) {
    return {
      link: function (scope, element, attrs) {
        var attr = attrs.initFromForm || attrs.ngModel || element.attrs('name'),
        val = attrs.value;
        if (attrs.type === "number") {val = parseInt(val)}
        $parse(attr).assign(scope, val);
      }
    };
  });

Widzisz, zdefiniowałem kilka błędów, aby uzyskać nazwę modelu. Możesz użyć tej dyrektywy w połączeniu z dyrektywą ngModel lub powiązać z czymś innym niż $ scope, jeśli wolisz.

Użyj tego w ten sposób:

<input name="test" ng-model="toaster.test" value="hello" init-from-form />
{{toaster.test}}

Uwaga: będzie to również działać z obszarami tekstowymi i wybierz menu rozwijane.

<textarea name="test" ng-model="toaster.test" init-from-form>hello</textarea>
{{toaster.test}}
superluminarny
źródło
Oto spakowany moduł, który implementuje rozwiązanie podobne do opisanego tutaj github.com/platanus/angular-keep-values
Agustin
1
Świetne rozwiązanie, ale będzie działać tylko z input="text". Jeśli masz numberrzut rzuci Model nie jest typu number docs.quarejs.org/error/ngModel/numfmt?p0=333
smoksnes
2
Aby wesprzeć liczby, możesz dodać if (attrs.type === "number") val = parseInt(val);
smoksnes,
@smoksnes - masz całkowitą rację. Zaktualizowałem odpowiedź :)
superluminarium
7

Aktualizacja: Moja pierwotna odpowiedź polegała na tym, że kontroler zawiera kod rozpoznający DOM, co łamie konwencje Angular na korzyść HTML. @dmackerman wspomniał o dyrektywach w komentarzu do mojej odpowiedzi i do tej pory całkowicie tego brakowało. Dzięki tym wejściom oto właściwy sposób na zrobienie tego bez łamania konwencji Angular lub HTML:


Jest też sposób na uzyskanie obu - pobierz wartość elementu i użyj go do aktualizacji modelu w dyrektywie:

<div ng-controller="Main">
    <input type="text" id="rootFolder" ng-model="rootFolders" disabled="disabled" value="Bob" size="40" />
</div>

i wtedy:

app.directive('input', ['$parse', function ($parse) {
    return {
        restrict: 'E',
        require: '?ngModel',
        link: function (scope, element, attrs) {
            if(attrs.value) {
                $parse(attrs.ngModel).assign(scope, attrs.value);
            }
        }
    };
}]);

Możesz oczywiście zmodyfikować powyższą dyrektywę, aby zrobić więcej z valueatrybutem przed ustawieniem modelu na jego wartość, w tym używając $parse(attrs.value, scope)do traktowania valueatrybutu jako wyrażenia kątowego (chociaż prawdopodobnie użyłbym do tego innego atrybutu [niestandardowego] osobiście, więc standardowe atrybuty HTML są konsekwentnie traktowane jako stałe).

Istnieje również podobne pytanie w temacie Udostępnianie danych dostępnych w szablonie dla modelu ng, które również może być interesujące.

Dan Hunsaker
źródło
Nie powinieneś dokonywać żadnych manipulacji / wykrywania DOM w swoich kontrolerach. Zamiast tego należy użyć dyrektywy.
dmackerman
2
W swojej odpowiedzi wyraźnie wspomniałem o tej wadzie. Państwo nie powinno , ale możliwe . Wszystko zależy od tego, czy ważniejsze jest przestrzeganie konwencji Angulara czy HTML. Ponieważ Angular łamie HTML.
Dan Hunsaker
3
Och, jestem manekinem. Zupełnie brakowało mi trochę na temat korzystania z dyrektywy. Odpowiedź odpowiednio zaktualizowana. Serdecznie przepraszamy za szarpanie, @dmackerman.
Dan Hunsaker,
Dzięki za dyrektywę! To dało mi pomysły do ​​zastosowania w projekcie, nad którym pracuję, gdzie generuję część serwera treści, a następnie muszę go użyć jako mojego modelu w kliencie.
ggalmazor
Cieszę się, że mogłem pomóc. Oczywiście, ogólnie rzecz biorąc, będziesz chciał zbudować zawartość po stronie serwera jako JSON i na tej podstawie zmusić aplikację do manipulowania modelem, ale czasem przydatne są inne opcje, a to tylko jedna.
Dan Hunsaker
7

Jeśli korzystasz z dyrektywy AngularJs ngModel, pamiętaj, że wartość valueatrybutu nie wiąże się z polem ngModel. Musisz go zainicjować samodzielnie, a najlepszym sposobem na to jest:

<input type="text"
       id="rootFolder"
       ng-init="rootFolders = 'Bob'"
       ng-model="rootFolders"
       disabled="disabled"
       value="Bob"
       size="40"/>
Hazarapet Tunanyan
źródło
Dziwnie jest zainicjować go w dyrektywie / znacznikach zamiast w kontrolerze.
random_user_name
5

To niewielka modyfikacja wcześniejszych odpowiedzi ...

$ Parsowanie nie jest potrzebne

angular.directive('input', [function () {
  'use strict';

  var directiveDefinitionObject = {
    restrict: 'E',
    require: '?ngModel',
    link: function postLink(scope, iElement, iAttrs, ngModelController) {
      if (iAttrs.value && ngModelController) {
        ngModelController.$setViewValue(iAttrs.value);
      }
    }
  };

  return directiveDefinitionObject;
}]);
dale.lotts
źródło
należy pamiętać, że ngModelController. $ setViewValue zmieni stan modelu na brudny i nieskazitelny na false, co również wpłynie na stan formy, która może być z czasem bólem.
Atul Chaudhary
2

Cześć, możesz wypróbować poniższe metody przy inicjalizacji modelu.

Tutaj możesz zainicjować model ng pola tekstowego na dwa sposoby

- Z użyciem ng-init

- Z użyciem $ scope w js

<!doctype html>
 <html >
 <head>
        <title>Angular js initalize with ng-init and scope</title>
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
</head>
<body ng-app="app" >
    <h3>Initialize value with ng-init</h3>
    <!-- Initlialize model values with ng-init -->
    <div ng-init="user={fullname:'Bhaskar Bhatt',email:'[email protected]',address:'Ahmedabad'};">
        Name : <input type="text" ng-model="user.fullname" /><br/>
        Email : <input type="text" ng-model="user.email" /><br/>
        Address:<input type="text" ng-model="user.address" /><br/>

    </div>  
    <!-- initialize with js controller scope -->
    <h3>Initialize with js controller</h3>

    <div  ng-controller="alpha">
        Age:<input type="text" name="age" ng-model="user.age" /><br/>
        Experience : <input type="text" name="experience" ng-model="user.exp" /><br/>
        Skills : <input type="text" name="skills" ng-model="user.skills" /><br/>
    </div>  

</body> 
<script type="text/javascript">
        angular.module("app",[])
        .controller("alpha",function($scope){
            $scope.user={};
            $scope.user.age=27;
            $scope.user.exp="4+ years";
            $scope.user.skills="Php,javascript,Jquery,Ajax,Mysql";
        });

     </script>
 </html>                
Bhaskar Bhatt
źródło
0

Problem polega na tym, że musisz ustawić model ng jako element nadrzędny w miejscu, w którym chcesz ustawić wartość / wartość ng. Jak wspomniano w Angular:

Jest używany głównie w elementach wejściowych [radiowych] i elementach opcjonalnych, więc gdy element jest wybrany, ngModel tego elementu (lub jego elementu nadrzędnego select) jest ustawiany na związaną wartość.

Np .: To jest wykonany kod:

<div class="col-xs-12 select-checkbox" >
<label style="width: 18em;" ng-model="vm.settingsObj.MarketPeers">
  <input name="radioClick" type="radio"  ng-click="vm.setPeerGrp('market');" 
         ng-value="vm.settingsObj.MarketPeers" 
         style="position:absolute;margin-left: 9px;">
  <div style="margin-left: 35px;color: #717171e8;border-bottom: 0.5px solid #e2e2e2;padding-bottom: 2%;">Hello World</div>
</label>
</div>

Uwaga: W powyższym przypadku już miałem odpowiedź JSON na model ng i wartość, właśnie dodałem inną właściwość do obiektu JS jako „MarketPeers”. Model i wartość mogą więc zależeć od potrzeb, ale myślę, że ten proces pomoże, zarówno mieć model ng, jak i wartość, ale nie mieć ich na tym samym elemencie.

sg28
źródło
0

Miałem podobny problem. Nie mogłem używać value="something"do wyświetlania i edycji. Musiałem użyć poniższego polecenia wewnątrz mojego <input>modelu z deklarowanym modelem.

[(ngModel)]=userDataToPass.pinCode

Gdzie mam listę danych w obiekcie userDataToPassoraz element, który muszę wyświetlić i edytować pinCode.

Z tego samego powodu nawiązałem do tego filmu na YouTube

tkrloltkr
źródło
W tym poradniku OP używa AngularJS, twoje referencje do filmu na YT używają Angular 4.
Chris22