Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I've learned the basics about AngularJS but I've just hit a wall. I want a directive that creates a textbox where I can respond to changes in the value using $observe. I've tried everything I can think of but I guess I'm missing something fundamental. I am getting 'undefined - Fubar!' in the console on page refresh but no further logs when the value changes. Here's what I have at the moment:

HTML

<attr-peek attr1="{{fubar}}"></attr-peek>

Javascript

app.controller("observeController", function ($scope) {
    $scope.fubar = "Fubar!";
});

app.directive("attrPeek", function () {
    return {
        restrict: "E",
        replace: true,
        template: "<input type='text' value='{{attr1}}' />",
        scope: { attr1: "@" },
        link: function (scope, element, attrs, controller) {
            console.log(attrs);
            attrs.$observe("value", function (newValue, oldValue) {
                console.log(oldValue + " - " + newValue);
            });
        }
    };
});

Fiddle http://jsfiddle.net/kp226/

If someone could show me how to do this I'd really appreciate it.

share|improve this question
    
The callback function used in attrs.$observe (annoyingly) only takes the new value as an argument (which is why you're getting "undefined - Fubar!" logs). –  Spiny Norman Mar 13 at 14:21

2 Answers 2

You are using $observe incorrectly. The first parameter is the name of the attribute to observe that is passed into the scope. You cannot use $observe on HTML properties such as value

link: function (scope, element, attrs, controller) {
     attrs.$observe("attr1", function (newValue, oldValue) {
          console.log(oldValue + " - " + newValue);
     });
 }
share|improve this answer
    
That makes sense but there must be something else wrong because it still doesn't work. –  Mark May 28 '14 at 4:35
    
Can you make a short, isolated JSFiddle? –  Sam P May 28 '14 at 4:36
    
JSFiddle added to question. –  Mark May 28 '14 at 6:35
1  
You need two-way binding if you want it to update when the input is changed. Take a look at this JSFiddle: jsfiddle.net/LG6zV –  Sam P May 28 '14 at 6:58

What's happening here is that, as Sam points out, is that you can only $observe an interpolated attribute value (that is, with the {{}} in it), which is different from the value property. The value attribute provides the default value for the value property.

attrs.$observe works one-way: you can only check for changes in the attribute value. Your directive is currently observing the value of attr1, which is bound to the value of fubar in the parent scope. If you would change the value of fubar, the value attribute of the input box would change accordingly.

When you change the value property (by typing into the input box), the value attribute doesn't change.

Luckily, there already is a directive that watches the value property of an input element: ng-model. You can test all of this by adding a second element next to your current textbox (as in this fiddle):

<input ng-model="fubar"></input>

As you will see, both inputs will display "Fubar!", the value of the scope field. Try changing the text in the ng-model textbox, the value of the other textbox will change as well, because its value attribute gets changed and its value property has not been changed from the default. Next, type into the dependent input box. You will see that the mg-model input does not change. What's more, if you now type into the ng-model box, the dependent input box now does not change, because it does not use the default value anymore. Notice that your $observe handler does still log the change of the default value in the console.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.