AngularJS: How to target specific directive with multiple instances - angularjs

I have multiple instances of a directive and I would like to target a specific instance only. For example in the code below, how can I make sure that the div with class="one" is the only one that gets triggered by the event $rootScope.$broadcast('myEvent').
JS:
myApp.directive('myDirective', function() {
return {
restrict: 'A',
controller: function(scope, el, attrs) {
scope.$on('myEvent', function() {
el.css({left: '+=100'});
});
},
};
});
HTML:
<div my-directive class="one"></div>
<div my-directive class="two"></div>

You should do this check in your event handler:
myApp.directive('myDirective', function() {
return {
restrict: 'A',
controller: function(scope, el, attrs) {
scope.$on('myEvent', function(ev,args) {
//do the check - you could provide a function, a value or something else
if(el.hasClass(args.class)){
el.css({left: '+=100'});
}
});
},
};
});
Then add the parameters in the $broadcast
$rootScope.$broadcast('myEvent',{class:'one'})

You could define a new attribute for this directive which references a callback that then is executed inside the callback of $on:
myApp.directive('myDirective', function() {
return {
restrict: 'A',
scope: {
callme: "="
},
controller: function(scope, el, attrs) {
scope.$on('myEvent', function() {
scope.callme(el)
});
},
};
});
HTML declaration:
<div my-directive class="one" callme="functionDefinedInScope"></div>
In your Controller scope:
$scope.functionDefinedInScope = function(el) {
el.css({left: '+=100'});
}
Read more about this here:
http://docs.angularjs.org/guide/directive (Section "Directive Definition Object")

can you use id instead of class
<div my-directive id="one"></div>
<div my-directive id="two"></div>
and in your controller
controller: function(scope, el, attrs) {
scope.moveElement = function() {
el.css({left: '+=100'});
}
}
and then instead of broadcast,
angular.element('#one').scope().moveElement()

Related

How to pass model variables from one directive to other using same controller for both directives?

Lets say i have a controller A:
app.controller('A', function($scope) {
$scope.commonvalue = "";
})
app.directive('dir1', function() {
return {
restrict: 'E',
templateUrl: 'template1.html',
controller: 'A'
};
});
app.directive('dir2', function() {
return {
restrict: 'E',
templateUrl: 'template2.html',
controller: 'A'
};
});
DIR1
template1.html:
<label>Enter value: </label>
<input ng-model="commonvalue"> </input>
DIR2
template2.html:
<p> The value of commonvalue variable is {{ commonvalue }} </p>
All i want to do is change the value of commonvalue from dir1 and get its value in dir2. One solution is to make the commonvalue variable in $rootScope. but i do not want to do that. I only want to change it in 'A' Controllers scope.
You can try something like this.
<div ng-app="myapp" ng-controller="myCtrl">
<my-changer ng-model="someVal"></my-changer>
<my-receiver ng-model="someVal"></my-receiver>
</div>
angular.module("myapp", [])
.controller("myCtrl", function($scope){
$scope.someVal = "Hello";
}).directive("myChanger", function(){
return {
restrict: "E",
scope: {
txtVal : "=ngModel"
},
template: "<input type='text' ng-model='txtVal'/>",
link: function(scope, elem, attr, ngModelCtrl){
}
};
}).directive("myReceiver", function(){
return {
restrict: "E",
scope: {
txtVal : "=ngModel"
},
template: "<input type='text' ng-model='txtVal'/>",
link: function(scope, elem, attr, ngModelCtrl){
}
}
});
JSFiddle
--EDIT---
If you are looking for one way binding then do this.
angular.module("myapp", [])
.controller("myCtrl", function($scope){
$scope.someVal = "Hello";
}).directive("myChanger", function(){
return {
restrict: "E",
scope: {
txtVal : "=ngModel"
},
template: "<input type='text' ng-model='txtVal'/>",
link: function(scope, elem, attr, ngModelCtrl){
}
};
}).directive("myReceiver", function(){
return {
restrict: "E",
scope: {
txtVal : "=ngModel"
},
template: "<p ng-bind='txtVal'/>",
link: function(scope, elem, attr, ngModelCtrl){
}
}
});
Updated JSFiddle
what you want is actualy normal behavior.
when you dont specify a scope for your directive, it will inherit properties from its controller, and when ever a value changes it'll reflect back in the controller..
see this plnkr
app.controller('MainCtrl', function($scope) {
$scope.obj = {};
$scope.obj.commonvalue = "initial value";
});
app.directive('dir1', function() {
return {
restrict: 'A',
templateUrl: 'dir1.html'
}
})
app.directive('dir2', function() {
return {
restrict: 'A',
templateUrl: 'dir2.html'
}
})
I've updated the answer to use a 'dotted' ng-model, I think that was your issue at first. You can review my answer where it is explained why it's important.
from the answer:
What happens is that the child scope gets its own property that hides/shadows the parent property of the same name
You can define scope variable with '=' char in your directives and pass 'commonvalue' to them:
https://jsbin.com/fobofepuji/1/edit?html,js,output

how to pass variable from controller to directive using click event in angularjs

i am using directive concept in angularjs to pass data varible from controller to directive.i am writing one html page and controller,directive in angularjs.
test.html:
<div ng-controller="myController"
data-angular-treeview="true"
data-tree-model="roleList"
data-node-id="roleId"
data-tree-id="mytree"
data-node-label="roleName"
data-node-children="children"
data-ng-click="selectNode(currentNode)"
>
</div>
testcontroller.js:
(function(){
app.controller('myController', function($scope,$http,TreeService){
$scope.selectNode=function(val)
{
$scope.nodeval=val.roleName;
alert("select:"+$scope.nodeval);
};
});
})();
testdirective.js:
app.directive('tree1', function($rootScope) {
function compile(scope, element, attributes) {
return {
post:function(scope, iElement, iAttrs) {
iElement.bind('click', function() {
alert("click: "+scope.node);
});
}
};
}
return {
compile: compile,
scope: {
},
restrict: 'AE',
};
});
here i am getting selected node name in testcontroller.js but i want to pass that nodename in my directive so please suggest me how to this.
Thanks
What i would do is define inside the directive isolated scope an attribute like this:
scope: {
node: '='
}
And inside the view controller have a node initialized as $scope.node = {}; and with the click event change the value of the local $scope.node to the node you are interested in, and as the directive recieved the reference to the $scope.node attribute inside the view controller, it would automatically update itself
<div test-directive node-value="node"></div>
isolate scope directive:
directive('testDirective', function(){
return {
restrict: 'EA',
scope: {
nodeValue: '='
},
link: function(scope, element, attrs){
console.log(scope.nodeValue);
}
}
Access controller scope:
directive('testDirective', function(){
return {
restrict: 'EA',
link: function(scope, element, attrs){
console.log(scope.$eval(attrs['nodeValue']));
}
}

How can I get my directive to access the controllers scope

I have a setup like this:
<controller>
<directive>
in my controller that has a function that returns an html string. How can I get my directive to render this by accessing the controllers scope?
Or maybe I should just put the controller in the directive?
app.controller('controller', ['$scope', 'DataService', function ($scope, DataService) {
$scope.parseJson = function () {
//returns the html
};
}]);
directive
app.directive('Output', function () {
return {
restrict: 'A',
replace: true,
template: '<need html from controller>',
link: function(scope, element, attr) {
//render
//scope.parseJson();
}
};
});
You should use the isolated scope: '&' option
app.directive('output', ['$sce', function ($sce) {
return {
restrict: 'A',
replace: true,
template: "<div ng-bind-html='parsed'></div>",
scope:{
output: "&"
},
link: function(scope){
scope.parsed = $sce.trustAsHtml(scope.output());
}
};
}]);
Template:
<div output="parseJson()"></div>
The directive and the controller should be sharing the scope already. Don't bother using a template for the directive, just get the HTML string in you linking function (you already have the method call in there) and modify the element directly using element.html(). Take a look at the element docs for more info.
app.directive('Output', function ($compile) {
return {
restrict: 'A',
link: function(scope, element, attr) {
var templateString = scope.parseJson();
var compiledTemplate = $compile(templateString)(scope);
compiledTemplate.appendTo("TheElementYouWishtoAppendYourDirectiveTo");
}
};
});

When i require ngModel controller how do I access a property of the model controller

I am using ng-repeat and setting a model with it similar to the following
<div ng-repeat="thing in things" ng-model="thing" my-directive>
{{thing.name}}
</div>
then in my directive it looks something like this
.directive("myDirective, function () {
return {
require: 'ngModel',
link: function(scope, lElement, attrs, model) {
console.log(model.name);// this gives me 'NAN'
}
}
})
My question is how can I access the values in the model? I tried model.$modelValue.name but that did not work.
If you want to bind in a scoped value then you can use the '=' in an isolated. This will appear on the scope of your directive. To read the ng-model directive, you can use =ngModel:
.directive("myDirective", function () {
return {
scope: {
model: '=ngModel'
}
link: function(scope) {
console.log(scope.model.name); // will log "thing"
}
}
});
.directive("myDirective", function () {
return {
require: 'ngModel',
link: function(scope, lElement, attrs, model) {
console.log(attrs.ngModel); // will log "thing"
}
}
})
If your directive does not have isolated or child scope then you can do this:
.directive('someDirective', function() {
return {
require: ['^ngModel'],
link: function(scope, element, attrs, ctrls) {
var ngModelCtrl = ctrls[0];
var someVal;
// you have to implement $render method before you can get $viewValue
ngModelCtrl.$render = function() {
someVal = ngModelCtrl.$viewValue;
};
// and to change ngModel use $setViewValue
// if doing it in event handler then scope needs to be applied
element.on('click', function() {
var val = 'something';
scope.$apply(function() {
ngModelCtrl.$setViewValue(val);
});
});
}
}
});

Angularjs: set parent directive scope value with child directive

I'm not sure this is the way to do this, but my goal is the following:
I have a parent directive
Inside the parent directive's block, I have a child directive that will get some input from the user
The child directive will set a value in the parent directive's scope
I can take it from there
Of course the problem is that the parent and child directives are siblings. So I don't know how to do this. Note - I do not want to set data in the
Fiddle: http://jsfiddle.net/rrosen326/CZWS4/
html:
<div ng-controller="parentController">
<parent-dir dir-data="display this data">
<child-dir></child-dir>
</parent-dir>
</div>
Javascript
var testapp = angular.module('testapp', []);
testapp.controller('parentController', ['$scope', '$window', function ($scope, $window) {
console.log('parentController scope id = ', $scope.$id);
$scope.ctrl_data = "irrelevant ctrl data";
}]);
testapp.directive('parentDir', function factory() {
return {
restrict: 'ECA',
scope: {
ctrl_data: '#'
},
template: '<div><b>parentDir scope.dirData:</b> {{dirData}} <div class="offset1" ng-transclude></div> </div>',
replace: false,
transclude: true,
link: function (scope, element, attrs) {
scope.dirData = attrs.dirData;
console.log("parent_dir scope: ", scope.$id);
}
};
});
testapp.directive('childDir', function factory() {
return {
restrict: 'ECA',
template: '<h4>Begin child directive</h4><input type="text" ng-model="dirData" /></br><div><b>childDir scope.dirData:</b> {{dirData}}</div>',
replace: false,
transclude: false,
link: function (scope, element, attrs) {
console.log("child_dir scope: ", scope.$id);
scope.dirData = "No, THIS data!"; // default text
}
};
});
If you want that kind of communication, you need to use require in the child directive. That will require the parent controller so you need a controller there with the functionality you want the children directives to use.
For example:
app.directive('parent', function() {
return {
restrict: 'E',
transclude: true,
template: '<div>{{message}}<span ng-transclude></span></div>',
controller: function($scope) {
$scope.message = "Original parent message"
this.setMessage = function(message) {
$scope.message = message;
}
}
}
});
The controller has a message in the $scope and you have a method to change it.
Why one in $scope and one using this? You can't access the $scope in the child directive, so you need to use this in the function so your child directive will be able to call it.
app.directive('child', function($timeout) {
return {
restrict: 'E',
require: '^parent',
link: function(scope, elem, attrs, parentCtrl) {
$timeout(function() {
parentCtrl.setMessage('I am the child!')
}, 3000)
}
}
})
As you see, the link receives a fourth param with the parentCtrl (or if there is more than one, an array). Here we just wait 3 seconds until we call that method we defined in the parent controller to change its message.
See it live here: http://plnkr.co/edit/72PjQSOlckGyUQnH7zOA?p=preview
First, watch this video. It explains it all.
Basically, you need to require: '^parentDir' and then it will get passed into your link function:
link: function (scope, element, attrs, ParentCtrl) {
ParentCtrl.$scope.something = '';
}

Resources