angularJS share methods between directives - javascript

how do I share a method between two directives? When I try it now the console says scope.triggerInput(); is undefined; If I replace the scope.triggerinput with just a string it works. So I guess I do it somewhere wrong in the attribute.
app.directive('myImage', function () {
return{
restrict: 'A',
template: ' <img ng-src="images/needed/noPhoto.png"class="hover">',
link: function (scope, element, attr) {
element.bind('click', function () {
scope.triggerInput();
});
}
};
});
app.directive('myFileInput', function (httpPostFactory) {
return{
restrict: 'A',
scope: {
triggerInput: '='
},
link: function (scope, element, attr) {
scope.triggerInput = function () {
console.log('triggerInput');
element[0].click();
};
}
};
});
html
<div data-my-image></div>
<input data-my-file-input type="file" name="file" triggerInput='triggerInput()'>

Very good question! If I understand your situation correctly, Angular Service is what you need to use for situations like these.
app.service('clickResponder',function(){
var srvc={};
srvc.triggerInput=function(){
// Do your stuff here.
}
return srvc;
}
Now, to use this service, its very simple just inject it on your directive like below:
app.directive('myImage', function (clickResponder) {
return{
restrict: 'A',
template: ' <img ng-src="images/needed/noPhoto.png"class="hover">',
link: function (scope, element, attr) {
element.bind('click', function () {
clickResponder.triggerInput();
});
}
};
});
Thats all you need to do. Hope this helps you in some way!

Related

Directives in object created during app lifetime doesn't work

I've created some basic directive. It works well if I use it with some objects in html file
<some-directive some-data="123"></some-directive>
But if I dynamically load this object to my webpage:
//getting html source as a string, then appending it to DOM:
elem.html("<some-directive some-data='123'></some-directive>");
The directive doesn't work (object is being added properly to DOM)
app.directive('someDirective', function (notes, parts) {
return {
restrict: 'AE',
scope: {
someData: '='
},
link: function (scope, elem, attrs) {
console.log("directive fired");
}
};
});
What can I do to make it work properly?
For dynamic directives, you have to use $compile service that compiles scope into template. Look at sample below, <some-directive-wrapper /> will add <some-directive /> element into itself and compile scope value
var app = angular.module('app', []);
app.directive('someDirective', function () {
return {
restrict: 'AE',
scope: {
someData: '='
},
template: '<h2>someDirective compiled, someData is {{someData}}</h2>',
link: function (scope, elem, attrs) {
console.log("directive fired");
}
};
});
app.directive('someDirectiveWrapper', function ($compile) {
return {
restrict: 'AE',
link: function (scope, elem, attrs) {
//get value from ajax maybe
//and set to scope
scope.data = 123;
//replace directive with another directive
elem.html('<h1>someDirectiveWrapper compiled </h1>\n<some-directive some-data="data"></some-directive>');
//compile scope value into template
$compile(elem.contents())(scope);
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<some-directive-wrapper></some-directive-wrapper>
</div>

Angularjs directive

I want to have an attribute directive a bit similar to ng-model. I just want to additionally bind an input fields value to a scope variable (just in one direction input field -> scope variable). So I have just tried this directive but I can not get the directive called anyway.
script:
.directive('passivemodel', function () {
return {
restrict: "A",
scope: {
passivemodel: '='
},
link: function (scope, element, attrs) {
scope.$watch('passivemodel', function(newPassivemodel, oldPassivemodel) {
console.log("passive model", newPassivemodel);
});
}
};
})
html:
<input data-passivemodel="keyword">
Edit:
Hmmm .. based on vilo20 answer I am running into a very strange behavior.
while this code is working very well:
<input data-ng-model="keyword" data-passivemodel="keyword">
this one does not (note the value of passivemodel):
<input data-ng-model="keyword" data-passivemodel="keyword2">. Sure I have defined the variable in the controller.
Controller:
.controller('SearchController', function($scope, $routeParams, $search) {
$scope.search = new $search();
$scope.keyword = "";
$scope.keyword2 = "";
})
Edit2: here is a fiddle http://jsfiddle.net/HB7LU/12107/
try this:
.directive('passivemodel', function () {
return {
restrict: "A",
scope: {
passivemodel: '='
},
link: function (scope, element, attrs) {
console.log("passive model", scope.passivemodel);
$scope.$watch('passivemodel', function(newPassivemodel, oldPassivemodel) {
//put your logic when passivemodel changed
});
}
};
})
Hope it helps
Edit: Here is a plunker http://plnkr.co/edit/T039I02ai5rBbiTAHfzv?p=preview
Use the scope attribute:
.directive('passivemodel', function () {
return {
restrict: "A",
scope: {
"passivemodel": "="
},
link: function (scope, element, attrs) {
console.log("access passivemodel: ", scope.passivemodel);
}
};
})
Finally it was as simple as that:
.directive('modelRed', [function(){
return {
require: 'ngModel',
restrict: 'A',
scope: {},
link: function (scope, element, attrs, ngModel) {
scope.$watch(function () {
return ngModel.$modelValue;
}, function(newValue) {
scope.$parent[attrs.modelRed] = newValue;
//console.log(attrs.modelRed, newValue, scope);
});
}
}
}])
And in the html:
<p><input type="text" data-ng-model="testInput" data-model-red="redInput">{{redInput}}</p>
Of course you have to define testInput and redInput in the $scope object.

Why does this angularjs directive not show the bound document?

I have a directive with a bound doc model from controller. But the directive does not show the document?
HTML:
<div ng-app="myApp">TestApp:
<div ng-controller="TestController as Test">Testdoc controller: {{Test.doc}}
<br>
<test-me ng-init="abc=123" my-model="Test.doc">Testdoc directive: {{myDoc}} | {{abc}}</test-me>
</div>
</div>
JS:
var app = angular.module("myApp", []);
app.controller("TestController", function () {
this.doc = {
name: 'testname',
id: null
};
});
app.directive("testMe", function () {
return {
scope: {
myDoc: '=myModel'
},
link: function(scope, elem, attrs){
}
}
});
output HTML is still:
TestApp:
Testdoc controller: {"name":"testname","id":null}
Testdoc directive: <missing output of doc here>| 123
jsfiddle: http://jsfiddle.net/kx97y93k/14/
What i am doing wrong?
Solution was not to call {{myDoc}} in html directly but inside a template.
app.directive("testMe", function () {
return {
restrict: 'E',
template: '<div>Testdirective: {{myDoc}}<div>',
scope: {
myDoc: '=myModel'
},
link: function(scope, elem, attrs){
}
}
});
See updated jsfiddle: http://jsfiddle.net/kx97y93k/18/
Many thanks to #Mr_Green for that hint
add restrict : 'E' to the DDO, see below. Angular 1.2 uses restrict : 'A' if not explicitly set otherwise. For Angular 1.3 that became 'EA' and your directive would have worked. To make it work in your fiddle, change it as follows:
app.directive("testMe", function () {
return {
restrict : 'E',
scope: {
myDoc: '=myModel'
},
link: function(scope, elem, attrs){
}
}
});

Rewriting directives to not use isolate scope?

I have two simple directives that I want to apply to an element.
This directive gives focus to a particular element when a condition changes to be true:
.directive('focusOnCondition', function ($timeout) {
return {
restrict: 'A',
scope: {
condition: '=focusOnCondition',
},
link: function (scope, el, attr) {
scope.$watch('condition', function (value) {
if (value) {
$timeout(function () {
el[0].focus();
});
}
});
}
};
});
This directive calls a function when the user presses 'enter':
.directive('triggerOnEnter', function () {
return {
restrict: "A",
scope: {
func: '&triggerOnEnter'
},
link: function (scope, el, attr) {
$(el).keypress(function (event) {
if (event.which == 13) scope.func();
});
}
};
})
These two directives work separately, but they don't work if I try to apply them to the same element. For example:
<form ng-show="pastingResults">
<textarea placeholder="Paste results and press 'enter'"
ng-model="pastedResultData"
trigger-on-enter="pasteResults()"
focus-on-condition="pastingResults"></textarea>
<button type="submit" ng-click="pasteResults()">Submit</button>
</form>
Result in an error, [$compile:multidir] Multiple directives (...) on (...).
How can I resolve this? I am new to Angular JS, and 'put it in an isolated scope' is the only thing I know how to do when making directives. I assume it must be possible to implement these without using an isolated scope, but I don't know how.
Can anyone give an example?
If you remove the isolated scopes, you can access the options by looking at the attributes on the element directly using the attrs object passed to the linking function, together with $eval to evaluate it if needs be:
app.directive('focusOnCondition', function ($timeout) {
return {
restrict: 'A',
link: function (scope, el, attr) {
scope.$watch(attr.focusOnCondition, function (value) {
if (value) {
$timeout(function () {
el[0].focus();
});
}
});
}
};
});
and
app.directive('triggerOnEnter', function () {
return {
restrict: "A",
link: function (scope, el, attr) {
$(el).keypress(function (event) {
if (event.which == 13) {
scope.$eval(attr.triggerOnEnter);
}
});
}
};
});
These can be seen working at http://plnkr.co/edit/1iOBNVlmRxm8HGRrObBd?p=preview

Parser function does not get called for change in input textbox

I am new to parsers and formatters. I have a directive that will be doing validation on change of the model.One way to do this is the $watch but from what I understand that is not a good way since it allows the model to be updated.
So I was looking at parsers and tried this code
app.directive('myDirective', function($compile) {
return {
restrict: 'E',
require: 'ngModel',
scope: {
},
link: function($scope, elem, attr, ctrl) {
console.debug($scope);
ctrl.$formatters.push(function(value) {
console.log("hello1");
return value;
});
ctrl.$parsers.unshift(function(value) {
debugger;
console.log("hello");
return value;
});
}
};
});
But the parser function is never called. The formatter is called once. Please see the plunkr .Can anyone tell me what I am doing wrong ,why is the parser function not getting called when i type in the textbox ?
This is a late response, but for reference:
I think you where missing the "glue" that will call the $parsers while ui changes occurs. This should be something like:
app.directive('myDirective', function($compile) {
return {
restrict: 'E',
require: 'ngModel',
scope: {
},
link: function($scope, elem, attr, ctrl) {
console.debug($scope);
ctrl.$formatters.push(function(value) {
console.log("hello1");
return value;
});
ctrl.$parsers.unshift(function(value) {
return value;
});
scope.$watch('directive model here', function() {
ctrl.$setViewValue(<build model from view here>);
});
}
};
});
For a full reference please see this (awesome) post.
Your link function is not called because the associated DOM element is not changing, just the model is. This works:
HTML:
This scope value <input ng-model="name" my-directive>
JS:
app.directive('myDirective', function($compile) {
return {
require: 'ngModel',
link: function($scope, elem, attr, ctrl) {
ctrl.$parsers.unshift(function(value) {
console.log("hello");
});
}
};
});
See here for more on when the link function is called.

Categories