watch ng-model inside directive

喜欢而已 提交于 2019-12-07 04:44:18

问题


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?


回答1:


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




回答2:


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.



来源:https://stackoverflow.com/questions/20828046/watch-ng-model-inside-directive

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!