I have the following directive:
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.required = attrs.hasOwnProperty('required');
scope.pattern = attrs.pattern || '.*';
}
};
});
with the following template:
<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-required="required"></textarea>
<input ng-switch-default type="{{type}}" ng-model="value" class="form-control" id="input-{{id}}" ng-disabled="disabled" ng-required="required" pattern="{{pattern}}"/>
</div>
</div>
It is used by this form:
<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>
Which has this 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;
});
};
}).
The form is rendered fine, but when I click the Save
button, the user values are never updated.
How can I use the updated values from within the myInput directive in the controller scope?
Here's the basic problem. Your ng-model
is a primitive and is only being bound in one direction...it will update if parent object is changed, but since it is primitive it does not carry reference to parent object...just value. Thus updating the primitive does not update parent object that it's original value came from
Cardinal rule in angular...always have a dot in ng-model
Here's a solution that will pass the main user
object to directive scope, as well as the property of that object to use for each input
<my-input id="firstName" model="user" field="firstName" label="First name"></my-input>
Now need to pass the object from controller into the directive scope:
app.directive('myInput', function() {
return {
scope: {
/* other props*/
field: '@',
model:'='/* now have reference to parent object in scope*/
},
......
};
});
Then in markup for an input will use []
notation in order to get our dot in:
<input ng-model="model[field]".../>
DEMO
In order to use angular validation you will likely have to require
the ngModel
controller in your directive or use nested form
Your problem is the ng-switch
.
ng-switch
like ng-repeat
creates a new scope that inherits from the parent.
That means that if you have let's say:
$scope.foo = "hello";
And then you have something like:
<input type="text" ng-model="foo">
Inside a ng-switch
. When you update foo
it is going to create its own foo
that hides/shadows the parent foo
.
In other words, the input will show hello
but when you modify it, a new foo
is created hiding the parent one. That means that your parent one won't get updated (your problem).
That is not Angular.js issue, that is how Javascript works.
Normally you want to do a:
<input type="text" ng-model="foo.bar">
That way, you can play with the inheritance and instead of creating a new foo
it will just update the bar
on the parent.
Since that is not something you can do every time and maybe in your concrete use case you can't, the easy way is just to use $parent
:
<input type="text" ng-model="$parent.value">
That way inside your ng-switch you will use directly the parent value
.
I highly recommend you to read this ASAP: https://github.com/angular/angular.js/wiki/Understanding-Scopes
Example: http://plnkr.co/edit/z4D6Gk5fK7qdoh1mndzo?p=preview
Cheers.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With