Johann
Johann

Reputation: 29867

AngularJS model not updating while typing

In the following AngularJS code, when you type stuff into the input field, I was expecting the div below the input to update with what is typed in, but it doesn't. Any reason why?:

html

<div ng-app="myApp">
    <input type="text" ng-model="city" placeholder="Enter a city"  />
    <div ng-sparkline ng-model="city" ></div>
</div>

javascript

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

app.directive('ngSparkline', function () {
    return {
        restrict: 'A',
        require: '^ngModel',
        template: '<div class="sparkline"><h4>Weather for {{ngModel}}</h4></div>'
    }
});

http://jsfiddle.net/AndroidDev/vT6tQ/12/

Upvotes: 0

Views: 131

Answers (5)

sphinks
sphinks

Reputation: 1

the issue is that require option means that ngSparkline directive expects ngModel directive controller as its link function 4th parameter. your directive can be modified like this:

app.directive('ngSparkline', function () {
    return {
        restrict: 'A',
        require: '^ngModel',
        template: '<div class="sparkline"><h4>Weather for {{someModel}}</h4></div>',
        link: function(scope, element, attrs, controller) {
            controller.$render = function() {
                scope.someModel = controller.$viewValue;
            }
        }
    }
});

but this creates someModel variable in scope. that I think isn't necessary for this use case.

fiddle

Upvotes: 0

user3620126
user3620126

Reputation: 21

template: '<div class="sparkline"><h4>Weather for {{city}}</h4></div>'

Upvotes: 0

drew_w
drew_w

Reputation: 10430

The basic issue with this code is you aren't sharing "ngModel" with the directive (which creates a new scope). That said, this could be easier to read by using the attributes and link function. Making these changes I ended up with:

HTML

<div ng-sparkline="city" ></div>

Javascript

app.directive('ngSparkline', function ($compile) {
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
            var newElement = '<div class="sparkline"><h4>Weather for {{' + attrs.ngSparkline + '}}</h4></div>';
            element.append(angular.element($compile(newElement)(scope)));
        }
    }
});

Using this pattern you can include any dynamic html or angular code you want in your directive and it will be compiled with the $compile service. That means you don't need to use the scope property - variables are inherited "automatically"!

Hope that helps!

See the fiddle: http://jsfiddle.net/8RVYD/1/

Upvotes: 1

Prasad K - Google
Prasad K - Google

Reputation: 2584

Add ngModel to the scope as mentioned below -

app.directive('ngSparkline', function () {
    return {
        restrict: 'A',
        require: '^ngModel',
        scope: {
            ngModel: '='
        },
        template: '<div class="sparkline"><h4>Weather for {{ngModel}}</h4></div>'
    }
});

Updated Fiddle

Upvotes: 1

XrXr
XrXr

Reputation: 2057

It should be

template: '<div class="sparkline"><h4>Weather for {{city}}</h4></div>'

since you are binding the model to city

JSFiddle

Upvotes: 1

Related Questions