I created two directives:
directivesModule.directive("capital", function () {
return {
scope: {
capital: "#"
},
link: function () {}
}
})
directivesModule.directive("country", function () {
return {
scope: {
country: "#"
},
link: function () {}
}
})
Next, I use them in the same element:
<div country="Russia" capital="Moscow"></div>
As a result, I get an error: Error: [$compile:multidir] Multiple directives [capital, country] asking for new/isolated scope on: <div country="Russia" capital="Moscow">
How do I get the attribute values without scope?
These directives will not necessarily be used in conjunction.
According to your code, you don't need isolated scope to get attribute value. Just use this:
directivesModule.directive("capital", function ($parse) {
return {
link: function (scope, element, attrs) {
// get attrs value
attrs.capital
}
}
})
Related
I have angular directive that looks like this
app.directive('paymentsTable', ['$watch', function($watch) {
return {
replace: true,
restrict: 'EACM',
templateUrl: '../views/paymentTable.html',
link: function(elem, attr, scope) {
console.log(elem.$parent.payments); // array
scope.$watch(function(elem) { return elem.$parent.payments }, function(value, oldValue) {
});
}
};
}]);
It gives me
angular.js:13920Error: [$injector:unpr]
When I rewrite first line like this
app.directive('paymentsTable', [ function() {
It gives me another error
angular.js:13920TypeError: o.$watch is not a function
I also use uglify. So, my question is: what is going on here?
The $watch function is part of scope that is handed to you in the link method, therefore there is no need to inject it. The reason you get the second error is the order of the link arguments. Try it like this:
app.directive('paymentsTable', function() { // no need for injection
return {
replace: true,
restrict: 'EACM',
templateUrl: '../views/paymentTable.html',
link: function(scope, element, attrs) { // The correct arguments order
console.log(elem.$parent.payments);
scope.$watch(function(elem) { return elem.$parent.payments }, function(value, oldValue) {
});
}
};
});
I am trying to write an attribute type directive.
I also want this attribute type directive to be added conditionally.
I also want to pass an object to this directive.
This is what I am so far:
js
.directive('autocompleteDirective', ['$timeout', function (timeout) {
return {
restrict:"A",
templateUrl: currentScriptPath.replace('.js', '.html'),
link: function (scope, el, attr) {
el.autocomplete({
source: scope.model,
select: function () {
timeout(function () {
el.trigger('input');
},0)
}
});
},
scope: {
model: '='
}
};
}]);
html
<textarea ng-attr-autocomplete-directive="{{param.autocomplete}}" ng-switch-when="textarea" ng-model="param.value" validator="{{param.validator || 'empty'}}" />
i want something like or better than
<textarea ng-attr-autocomplete-directive="{{shouldadd? param.autocomplete:false}}" ng-switch-when="textarea" ng-model="param.value" validator="{{param.validator || 'empty'}}" />
I am working on an angular project and I use a directive to create an isolated scope. The directive looks like this:
var directive = module.directive('question', function () {
return {
restrict: 'E',
templateUrl: 'question.html',
transclude: true,
scope: {
quiz: '=quiz'
},
link: function (scope, attr, element) {
scope.$watch(function () {
return scope.quiz;
},
function (oldVal, newVal) {
scope.currentQuestion = scope.quiz;
});
}
};
});
For I do not want to bind to a property (or field) in my Controller, I created a function and call the directive this way:
<question quiz="quiz.getCurrentQuestion()">... (transcluding stuff)</question>
Please note that quiz is my Controller using the as-Syntax.
The way I process the directive is working, but I don't like to create a two-way-binding ( to an R-value?).
Now I tried to just pass the function using &-binding but this just turns out odd results in the link-function and breaks everything.
Can I use the function-binding using & and somehow call the function (in my template or in the link-function) to get the result I need to make it work like two-way-binding?
Thank you for your help.
EDIT
The return value of the getCurrentQuestion-function is an object which looks like
{
questionNumber: 1,
answers: [],
getQuestionText() : function(...),
...
}
So nothing to special, I hope...
EDIT 2
When I use
...
scope: {
quiz: '&quiz'
}
then in the $watch-function I get
function(locals) { return parentGet(scope, locals); } for scope.quiz
And if I call the function like scope.quiz() I get undefined as result.
Couldn't find any way to watch a function in scope binding. However, there are other solutions. If you want single way binding you can use '#', but that means that you would have to parse the JSON in the watch ( working example):
var directive = module.directive('question', function () {
return {
restrict: 'E',
templateUrl: 'question.html',
transclude: true,
scope: {
quiz: '#'
},
link: function (scope, attr, element) {
scope.$watch('quiz', function (newVal, oldVal) {
scope.currentQuestion = angular.fromJson(newVal);
});
}
};
});
It works, but if you have a high rate of updates, the overhead can be annoying. What I would do, is use a service that holds all the questions, and both controller and directive can talk to. When the current question is changed, the controller should pass to the directive only the id of the new question (using simple # bind), and the directive would query the service for the question.
I'm relative new to AngularJS and trying to create a directive for add some buttons. I'm trying to modify the controller scope from inside the directive but I can't get it to work. Here is an example of my app
app.controller('invoiceManagementController', ['$scope', function ($scope) {
$scope.gridViewOptions = {
isFilterShown: false,
isCompact: false
};
}]);
app.directive('buttons', function () {
return {
restrict: 'A',
template: '<button type="button" data-button="search" title="Filter"><i class="glyphicon glyphicon-search"></i></button>',
scope: {
gridViewOptions: '='
},
transclude: true,
link: function (scope, element, attr, ctrl, transclude) {
element.find("button[data-button='search']").bind('click', function (evt) {
// Set the property to the opposite value
scope.gridViewOptions.isFilterShown = !scope.gridViewOptions.isFilterShown
transclude(scope.$parent, function (clone, scope) {
element.append(clone);
});
});
}
};
});
My HTML like following
{{ gridViewOptions.isFilterShown }}
<div data-buttons="buttons" data-grid-view-options="gridViewOptions"></div>
The scope inside the directive does change but is like isolated, I did try paying with the scope property and transclude but I'm probably missing something, would appreciate some light here
When you modify scope inside of your directive's link function, you are modifying your directive's isolated scope (because that is what you have set up). To modify the parent scope, you can put the scope assignment inside of your transclude function:
transclude(scope.$parent, function (clone, scope) {
// Set the property to the opposite value
scope.gridViewOptions.isFilterShown = !scope.gridViewOptions.isFilterShown
element.append(clone);
});
Ok finally found a solution for this after some more research today. Not sure if the best solution, but this works so good for now.
app.controller('invoiceManagementController', ['$scope', function ($scope) {
$scope.gridViewOptions = {
isFilterShown: false,
isCompact: false
};
}]);
app.directive('buttons', function () {
return {
restrict: 'A',
template: '<button type="button" data-button="search" data-ng-class="gridViewOptions.isFilterShown ? \'active\' : ''" title="Filter"><i class="glyphicon glyphicon-search"></i></button>',
scope: {
gridViewOptions: '='
},
link: function (scope, element, attr, ctrl, transclude) {
element.find("button[data-button='search']").bind('click', function (evt) {
scope.$apply(function () {
// Set the property to the opposite value
scope.gridViewOptions.isFilterShown = !scope.gridViewOptions.isFilterShown;
});
});
}
};
});
Is there a way to allow the user to give a method name to a directive, let the directive create that method on the scope, and then handle calls to that method?
So, first I let the user define a method name HELLO, and then I let the user call HELLO from elsewhere (still in the same scope)
<div ng-controller="AppController">
<div mydirective="" mydirective-data="MyJson" mydirective-fx="HELLO" />
<button ng-click="HELLO()">Click me</button>
</div>
Internally, the directive should see the HELLO and map it to its own method. In the directive, I am looking at the method name being passed in and assigning it
app.directive('mydirective', function() {
return {
restrict: 'A',
scope: {
data: '=mydirectiveData',
fx: '=mydirectiveFx'
},
link: function(scope, element, attrs) {
scope.fx = function () { console.log(scope.data); } ;
}
}
}
);
as you can see, I am assigning scope.fx, which should be HELLO, to a function which should read scope.data, defined in the controller.
Attempting this does not do anything nor does it throw an error. It makes me wonder if I am doing this the wrong way.
For clarity, I have created a plunker. Remember to open the console.
Use # instead of = then scope[scope.fx] to create the property:
app.directive('mydirective', function() {
return {
restrict: 'A',
scope: {
data: '=mydirectiveData',
fx: '#mydirectiveFx'
},
link: function(scope, element, attrs) {
scope[scope.fx] = function () { console.log(scope.data); };
}
}
}
);
http://plnkr.co/edit/a2c14O?p=preview