Tengo la siguiente directiva:
directive('myInput', function() { return { restrict: 'AE', scope: { id: '@', label: '@', type: '@', value: '=' }, templateUrl: 'directives/dc-input.html', link: function(scope, element, attrs) { scope.disabled = attrs.hasOwnProperty('disabled'); scope.requinetworking = attrs.hasOwnProperty('requinetworking'); scope.pattern = attrs.pattern || '.*'; } }; });
con la siguiente plantilla:
<div class="form-group"> <label for="input-{{id}}" class="col-sm-2 control-label">{{label}}</label> <div class="col-sm-10" ng-switch on="type"> <textarea ng-switch-when="textarea" ng-model="value" class="form-control" id="input-{{id}}" ng-disabled="disabled" ng-requinetworking="requinetworking"></textarea> <input ng-switch-default type="{{type}}" ng-model="value" class="form-control" id="input-{{id}}" ng-disabled="disabled" ng-requinetworking="requinetworking" pattern="{{pattern}}"/> </div> </div>
Es usado por esta forma:
<form ng-controller="UserDetailsCtrl" role="form" class="form-horizontal"> <div ng-show="saved" class="alert alert-success"> The user has been updated. </div> <my-input label="First name" value="user.firstName" id="firstName"></my-input> <my-input label="Last name" value="user.lastName" id="lastName"></my-input> <my-input label="Email" value="user.email" id="email" type="email" disabled></my-input> <my-input label="Password" value="user.password" id="password" type="password"></my-input> <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <button ng-click="update()" class="btn btn-default">Save</button> </div> </div> </form>
Que tiene este controller:
controller('UserDetailsCtrl', function($scope, $stateParams, User) { $scope.user = User.get({userId: $stateParams.id}); /** * Update the current user in this scope. */ $scope.update = function() { console.log($scope.user); $scope.user.$update({userId: $scope.user.id}).then(function(results) { $scope.saved = true; }); }; }).
El formulario se procesa correctamente, pero cuando hago clic en el button Save
, los valores del usuario nunca se actualizan.
¿Cómo puedo usar los valores actualizados desde dentro de la directiva myInput en el scope del controller?
Aquí está el problema básico. Su ng-model
es una primitiva y solo está ligada en una dirección … se actualizará si se cambia el object padre, pero como es primitivo no lleva reference al object primario … solo valor. Por lo tanto, la actualización de la primitiva no actualiza el object principal de donde proviene su valor original
Regla cardinal en angular … siempre tiene un punto en ng-model
Aquí hay una solución que pasará el object del user
principal al scope de la directiva, así como la propiedad de ese object para usar para cada input
<my-input id="firstName" model="user" field="firstName" label="First name"></my-input>
Ahora necesitamos pasar el object del controller al scope de la directiva:
app.directive('myInput', function() { return { scope: { /* other props*/ field: '@', model:'='/* now have reference to parent object in scope*/ }, ...... }; });
Luego, en el marcado para una input usaremos la notación []
para poner nuestro punto en:
<input ng-model="model[field]".../>
MANIFESTACIÓN
Para usar la validation angular, es probable que require
el controller ngModel
en su directiva o use una forma anidada
Tu problema es el ng-switch
.
ng-switch
como ng-repeat
crea un nuevo ámbito que henetworkinga del padre.
Eso significa que si tienes, digamos:
$ scope.foo = "hola";
Y luego tienes algo como:
<input type="text" ng-model="foo">
Dentro de un ng-switch
. Cuando actualice foo
, creará su propio foo
que ocultará / sombreará el foo
padre.
En otras palabras, la input mostrará " hello
pero cuando la modifique, se creará un nuevo " foo
ocultando el elemento principal. Eso significa que su padre no se actualizará (su problema).
Ese no es el problema de Angular.js, así es como funciona Javascript.
Normalmente quieres hacer un:
<input type="text" ng-model="foo.bar">
De esta forma, puedes jugar con la inheritance y en lugar de crear un nuevo foo
, simplemente actualizará la bar
en el padre.
Como eso no es algo que pueda hacer cada vez, y tal vez en su caso concreto de uso no pueda hacerlo, la manera más sencilla es usar $parent
:
<input type="text" ng-model="$parent.value">
De esa manera dentro de su ng-switch usará directamente el value
principal.
Le recomiendo que lea esto lo antes posible: https://github.com/angular/angular.js/wiki/ Understanding- Scopes
Ejemplo: http://plnkr.co/edit/z4D6Gk5fK7qdoh1mndzo?p=preview
Aclamaciones.