Directive not updated after factory call - angularjs

I have a custom directive that has a single attribute called content. I'm trying to pass data to this directive's attribute via an outer's controller scope variable called x. This seems to work fine by setting x equal to 'xyz' at the start of the controller, but when I make a call to a factory to pull a value to update the x variable the data isn't being reflected in the directive. I can see that $scope.x is being set to the return value from the factory within the controller, but it's not then updating the directive.
I seem to missing something somewhere. I'm guessing it's a scope problem but I'm just not seeing it. I've tried to simplify my issue into a Plunker (http://plnkr.co/edit/wsWzSTJ9VDprfTaToeHv).
Any thoughts?
Thanks
Chris

The basic problem as noted in the comments is a missing $watch in the directive controller.. the controller doesn't "know" that content variable has changed..
so adding a $watch in the controller (the directive controller!) would solve this:
$scope.$watch(function(){return $scope.content}, function(){
$scope.text = $scope.content
})
A working demo
Good luck!

Related

What is the disadvantage of using the $scope as variable in angularjs, to share $scope of a controller inside the app.run?

What is the disadvantage of using the $scope as variable in AngularJS, to share $scope of a controller inside the app.run()?
Actually I am doing that to make code generic to be called from all the controllers with same function in app.run().
The function I am using is with the
$rootScope.getUserInfo = function($scope){
$scope.userinfo = '---------';
}
where $scope is the variable that I am passing from every controller like that
$rootScope.getUserInfo($scope);
I don't think there's inherently something wrong with passing around a scope. People do this a lot in AngularJS services and it's internally done a lot, too: your created controller is passed a scope to work with.
However, I would say it's not necessary in your example to have getUserInfo to depend on a scope being passed. Why not return the user information and have the caller put it on the scope? That way, you can use it in parts of your app that don't have a scope.
Instead of using $scope, you can use var vm = this; and define everything in that controller with vm.variablename_or_funcname instead of $scope.variablename_or_funcname
And you can attach that controller in html like ng-controller = "mycontroller as vm"
More info:
https://johnpapa.net/angularjss-controller-as-and-the-vm-variable/

Angularjs directive: Passing a model reference to an isolated scope

I 'm trying to write a collapsible, reusable calculator directive, that binds to an input field (in the parent scope). This input field itself has a ngModel binding.
When the user presses the equals-button of my directive this parent scope model should be updated. I need to isolate the scope so I can reuse it:
Here is the simplified code and how I would like to use it:
http://plnkr.co/edit/OSOcxydJWh8K520nstAU?p=preview
I tried passing in the values as an attribute. but that does not work because I don't know how to update this attribute inside of the controller(I tried the $attrs service).
So how can I update the model from the directive?
Maybe you're overthinking it, maybe I'm underthinking it. Either way, here's all I did to change yours to make it work:
if ($scope.operator ==='+') {
$scope.field = parseInt($scope.field) + $scope.operand;
}
I uncommented your scope and then I made sure that your controller made reference to the data you had exposed in your scope. That's it.
And here's a working version of your Plunker: http://plnkr.co/edit/btBi3E
You need to use ngModelController. Here's a link with docs, with a handy example:
NgModelController

Controller scope object changes not reflected in directive $watch callback

I have a controller that has an object on its scope: $scope.objToTrack.
I have a directive that is inside a nested view that $watches for changes to that object.
It has isolate scope, but objToTrack is set as = so that it can be watched.
When I click the directive, it calls an expression that is a method on the controller which changes objToTrack.
Here's a plunker to illustrate my setup.
The problem is that objToTrack $watch callback isn't fired, although the object is changed.
If you switch between Test1 and Test2 states, changes made to objToTrack are visible. It's just that I don't understand why it doesn't work right away on click.
Thanks.
To answer question...if you bind your own event handlers to an element, and change angular scope within that event handler you need to call $apply so angular is made aware of the change and can run a digest
Example You have:
element.on('click',function(){
scope.onClick({number:RNG.int(200,300)});
});
Would need to be changed to:
element.on('click',function(){
scope.$apply(function(){
scope.onClick({number:RNG.int(200,300)});
});
});
It is a lot simpler if you use event directives already provided by angular. In this case you are writing considerable amount of extra code vs using ng-click. It also makes testing a lot easier when you stay within angular as much as possible
Also, if you want to pass an object into your directive you should not use curly braces.
In html, use obj-to-track="objToTrack", instead of obj-to-track="{{objToTrack}}".
Like this:
<div simple-directive obj-to-track="objToTrack" class="directive"></div>
And in directive.js: use '=' for bi-directional binding of the objToTrack.
Like this:
scope:{
objToTrack:'='
}
In your "test*.html" files, replace "on-click" by "ng-click".
"on-click" doesn't look in your current controller, "ng-click" does.

$rootScope's databinding could not get the right value

I write a demo to show this problem, when you change the select value, curTpl will change.
However, if you want to see the value of curTpl, the value don't change!
http://plnkr.co/edit/pm1pIomr625WkvpHrggc?p=preview
You need to inject $scope rather than $rootScope into the controller like this
controller('testCtrl', ['$scope', testCtrl]);
AngularJS creates a child scope automatically when compiled HTML template is executed. So the ng-model used in the template is in child scope. Since you tried to access the data in the controller, you have to access to the the same child scope as the template.

Angular - ngModel not updating when called inside ngInclude

First and foremost, the plunker: http://plnkr.co/edit/v1uTz5
This is a working demo of the issue I am running into.
I have a ng-include to include a partial.
Inside the partial I have an text input with ngModel AND directive.
The model updates accordingly inside the include, but any interaction outside the include is ignored. The {{test}} outside the include doesn't update, but the {{test}} inside does.
The directive, when called, handles the enter key and calls the correct scope and function. However, the $scope.test variable has never been updated, but $scope.testFinal is updated and the ng-include template renders it appropriately. Trying to reset the $scope.test model does not work either.
Am I missing something here? Or is this a bug with the directive or with the ng-include?
Instead of using a primitiive to define the variable, make it an object.
$scope.model={test:''};
Directives create their own scope for each item. When you equate a primitive to a new scope variable, it has no binding to the original, however when original is an object, a reference is created , not a copy, and changes made in one will reflect in the other
Simple explanatory example:
var a ='foo';
var b= a;
/* now change a*/
a='bar';
alert( b) // is still 'foo'
now do the same with object:
var obj_1= {a:'foo'};
var obj_2=obj_1;
/* now change obj_1.a*/
obj_1.a='bar';
alert( obj_2.a) // change to obj_1 will also change obj_2 and alert returns "bar"*/
Your Plunker Modified
Read this article on angular wiki for more detailed explanation
John Lindquist has a video about it. Although he doesn't quite explains why you need to use an object.
Basically every time there is a new non-isolated scope, every property of the parent scope is copied to the new scope and, as #charlietfl explained, copying a primitive type really creates a "copy" but with objects what you get is a reference, hence the changes are global.
ng-include creates its own scope and it is different than outer scope. Use this.test instead of $scope.test inside ng-include template. It will work properly.

Resources