Usually in Directives, I use require: 'ngModel' if I want to pass the scope to it. This works fine. But I am now creating a directive that creates 5 different HTML elements each with different ngModels that is passed from parent. The ngmodels that needs to be passed as attribute are ngModel1, ngModel2, ngModel3, ngModel4, ngModel5. How do I add multiple options in the require condition inside the directive?
I tried these and it doesnt work:
require: ['ngModel1', 'ngModel2', 'ngModel3', 'ngModel4', 'ngModel5'],
and
require: {'ngModel1', 'ngModel2', 'ngModel3', 'ngModel4', 'ngModel5'},
and
require: 'ngModel1', 'ngModel2', 'ngModel3', 'ngModel4', 'ngModel5',
and
require: 'ngModel1, ngModel2, ngModel3, ngModel4, ngModel5'},
How do I add multiple require options?
EDIT:
HTML code:
<div get-vehicles-checkbox
cars-ng-model="formData.cars"
bikes-ng-model="formData.bikes"
trucks-ng-model="formData.trucks"
van-ng-model="formData.van"
bus-ng-model="formData.bus"
></div>
Directive:
app.directive('getVehiclesCheckbox', function($compile) {
return {
restrict: 'A',
replace:true,
// require: ?
scope: {
carsNgModel: '=',
bikesNgModel: '=',
trucksNgModel: '=',
vanNgModel: '=',
busNgModel: '='
},
controller: 'SomeController',
link: function(scope, element, attrs, carsNgModel, bikesNgModel, trucksNgModel, vanNgModel, busNgModel) {
scope.carsNgModel = {},
scope.bikesNgModel = {},
scope.trucksNgModel = {},
scope.vanNgModel = {},
scope.busNgModel = {}
var html = '<span ng-repeat="car in cars">' +
'<input type="checkbox" ng-model="carsNgModel[car.code]"> {{ car.number }} {{ car.description }}' +
'</span>' +
'<span ng-repeat="bike in bikes">' +
'<input type="checkbox" ng-model="bikesNgModel[bike.code]"> {{ bike.number }} {{ bike.description }}' +
'</span>';
//.... etc.. etc.....
// COMPILE HTML
//... .... ...
}
}
});
app.directive('myDirective', function() {
return {
restrict: "A",
require:['^parentDirective', '^ngModel'],
link: function ($scope, $element, $attrs, controllersArr) {
// parentDirective controller
controllersArr[0].someMethodCall();
// ngModel controller
controllersArr[1].$setViewValue();
}
}
});
Related
I have custom directive and want to send some parameters(objects) to this directive.
In directive I have select list based on one of this parameters and I need to follow this parameter.
My directive:
<custom-directive rows="users">
</custom-directive>
and template:
<ui-select ng-model="value">
<ui-select-match allow-clear="true">
{{$select.selected}}
</ui-select-match>
<ui-select-choices repeat="row in rows | filter: $select.search">
<div>
<span ng-bind-html="row | highlight: $select.search"></span>
</div>
</ui-select-choices>
</ui-select>
normally if rows change ui-select will automatically update select list. But if rows is variable from outside of this directive, it wont.
Can I have the same variable outside and inside directive?
I think I can use ng-model, but I'm not sure it is good solution.
EDIT:
My directive code:
.directive('custom-directive', function () {
return {
restrict: 'E',
replace: true,
scope: {
rows: '='
},
templateUrl: 'template.html',
controller: ['$scope', function($scope) {
console.log($scope);
}]
};
})
You can modify your custom directive to work with ng-model in the following way:
directive('customDirective', function() {
return {
// ...
require: '?ngModel', // get a hold of NgModelController
link: function(scope, element, attrs, ngModel) {
if (!ngModel) return;
// Write data to the model
// Call it when necessary
scope.setValue = function(value) {
ngModel.$setViewValue(value);
}
}
};
});
Initial state of ng-model value can be retrieved using that method:
ngModel.$render = function() {
var value = ngModel.$viewValue || [];
};
You can use link instead of the controller to handle functionality with rows. Setting rows : '=' should already take care of the two-way binding.
.directive('custom-directive', function () {
return {
restrict: 'E',
replace: true,
scope: {
rows: '='
},
templateUrl: 'template.html',
link: function(scope, element, attr) {
console.log(scope.rows);
};
};
})
EDIT:
Add a watch to the value that you need to do behavior on external change.
.directive('custom-directive', function () {
return {
restrict: 'E',
replace: true,
scope: {
rows: '='
},
templateUrl: 'template.html',
link: function(scope, element, attr) {
scope.$watch('rows', function(oldValue, newValue) {
console.log('This is the newValue : ' + newValue);
};
};
};
})
I have the following code in angular.
<div vh-accordion-group id="{{$index}}" panel-class="panel-info">
<div vh-accordion-header> </div>
<div vh-accordion-body> </div>
</div>
The HTML for the accordion-group is :
<div class="panel panel-info" ng-transclude>
</div>
Also, the js for the same is :
home.directive("vhAccordionGroup", ['version', function (version) {
return {
restrict: 'EA',
replace: true,
transclude: true,
scope: {
panelClass: '#'
},
templateUrl: "JS/HomeModule/Directives/vhAccordion/vhAccordionGroup.html?v=" + version,
controller: ['$scope', '$element', function ($scope, $element) {
$scope.accordionId = $element.attr("id") + "vhAcc";
this.getAccordionId = function () {
return $scope.accordionId;
};
}],
link: function (scope, element, attrs, vhAccordionGroupController) {
element.addClass(scope.panelClass);
scope.accordionId = element.attr("id") + "vhAcc";
}
};
}]);
These accordions are called in a loop using ng-repeat.
The problem is the {{$index}} which I am passing in the Id is being taken as a string rather then an expression.
I need each of the accordions to have a unique Id so that they can open and close correctly.
Please let me know what I am missing, as I am a newbie to angular.
Simply add id to the isolated scope:
home.directive("vhAccordionGroup", ['version', function (version) {
return {
restrict: 'EA',
replace: true,
transclude: true,
scope: {
panelClass: '#',
id: '#'
},
templateUrl: "JS/HomeModule/Directives/vhAccordion/vhAccordionGroup.html?v=" + version,
controller: ['$scope', '$element', function ($scope, $element) {
$scope.accordionId = $scope.id + "vhAcc";
this.getAccordionId = function () {
return $scope.accordionId;
};
}],
link: function (scope, element, attrs, vhAccordionGroupController) {
element.addClass(scope.panelClass);
scope.accordionId = scope.id + "vhAcc";
}
};
}]);
Then, use $scope.id (and scope.id) instead of $element.attr. $element.attr gives access to the actual DOM element and so it makes sense that the value would not be interpolated.
Suppose, I have controller:
angular.module('tf').controller('Ctrl', function($scope){
$scope.params = {
orderBy: null
};});
And a directive "common":
angular.module('tf').directive("common", function() {
return {
restrict: 'E',
replace: true,
template: '<div><outer order-by="orderBy"><inner order-by-field="name1"></inner><inner order-by-field="name2"></inner></outer></div>',
controller: function ($scope) {
},
scope: {
orderBy: '='
},
link: function (scope, element, attrs) {
}
}});
Controller is using directive within it's template:
<div ng-app="tf">
<div ng-controller="Ctrl">
<common order-by="params.orderBy"></common>
<div style="color:red">{{params.orderBy}}</div>
</div>
This directive is using directive "outer":
angular.module('tf').directive("outer", function() {
return {
restrict: 'E',
transclude: true,
replace: true,
template: '<div ng-transclude></div>',
controller: function ($scope) {
this.order = function (by) {
$scope.orderBy = by
};
},
scope: {
orderBy: '=',
}
}});
Which is parent for the directive "inner":
angular.module('tf').directive("inner", function() {
return {
require: '^outer',
restrict: 'E',
transclude: true,
replace: true,
template: '<div ng-click="onClicked()">{{orderByField}}</div>',
controller: function ($scope) {
$scope.onClicked = function () {
$scope.outer.order($scope.orderByField);
}
},
scope: {
orderByField: '#'
},
link: function (scope, element, attrs, outer) {
scope.outer = outer;
}
}});
The directive "outer" shares "order" method with directive "inner" by it's controller. The directive "inner" is accessing it by using "require" mechanism.
For some reason, this is not working as expected (Property of the controller isn't updated each time it's changed by directive). If I place "orderBy" into object (e.g. {"order": {"by": null }} ) and use object instead of string value, everything is working as expected ( controller scope is properly updated by the directive). I know about "always use dots" best practices principle, but I don't wanna use it here, because it would make my directive's API less intuitive.
Here is jsfiddle:
http://jsfiddle.net/A8Vgk/1254/
Thanks
I'm trying to move my template from being in-line to it's own file. Everything was working before I changed from template to templateUrl
Glenn.directive('test', function($compile) {
return {
restrict: 'A',
priority: 1000,
terminal: true,
templateUrl: function(tElement, tAttrs) {
return ('test.html');
},
link: function(scope, element, attrs) {
attrs.$set('editable-text', 'content.' + attrs.edit + '.data');
attrs.$set('edit', null);
$compile(element)(scope);
}
}
});
test.html
{{ 'content.' + tAttrs.edit + '.data' }}
<button ng-click="' + tAttrs.edit + '_form'+ '.$show()" ng-hide="' + tAttrs.edit + '_form'+ '.$visible">edit</button>
Why isn't the tAttrs being passed to my template test.html?
I never seen this that way, i always pass an string to the templateUrl property like
...
templateUrl: './foodirective.tmpl.html'
...
You could assign the attrs from your directive element in the linking function:
myApp.directive('fooDirective', function(){
return{
restrict: 'E',
scope: true,
templateUrl: './foodirective.tmpl.html',
link: function(scope, elem, attrs){
// do stuff
scope.tAttrs = attrs;
}
}
})
I've prepared a plunk for you.
Say I have the following two directives:
angular.module('foo').directive('outer', [function(){
return {
restrict: 'E',
scope: {
inner: '#',
innneParams: '#'
},
template: "<div {{inner}}{{innerParams}}></div>",
link: function(scope, elem, attrs){
console.debug("I AM IN YOUR OUTER DIRECTIVE PASSING YOUR D00DZ!")
}
}
}]);
angular.module('foo').directive('innerDir', [function(){
return {
restrict: 'EA',
scope: {
innerParam: '='
},
template: "<div>{{massagedInner}}</div>",
link: function(scope, elem, attrs){
console.debug('I AM IN YOUR INNER DIRECTIVE MASSAGING YOUR D00DS!')
scope.massagedInner = scope.innerParam + "FROM YOUR DOGE!"
}
}
}]);
And the following HTML:
<outer inner="inner-dir" my-awesome-scope-value="myAwesomeScopeValue" inner-params="inner-param='myAwesomeScopeValue'"></outer>
The outer directive console debug triggers, the inner one does not. Is there a good way for me to achieve this kind of behaviour?
Plunk: http://plnkr.co/edit/jXbtWvYvtFXCTWiIZUDW?p=preview
There are quite a few things you're doing wrong. I've made the changes that I thought are close to what you wanted it to do and you can change the code from here.
Here's a working version
And this is what script.js now looks like;
angular.module('foo', []);
angular.module('foo').controller('fooController', ['$scope', function(scope){
scope.myAwesomeScopeValue = 'O HAI THERE'
}]);
angular.module('foo').directive('outer', [function(){
return {
restrict: 'E',
scope: {
// inner: '#',
// innnerParams: '#'
innerParam: '#'
},
template: "<div inner {{inner}} {{inner-param}}></div>",
link: function (scope) {
console.log('OUTER', scope.innerParam);
}
}
}]);
angular.module('foo').directive('inner', [function(){
return {
restrict: 'A',
// scope: {
// innerParam: '='
// },
replace: false,
template: "<div>{{massagedInner}}</div>",
link: function(scope, elem, attrs){
scope.massagedInner = scope.innerParam + "FROM YOUR DOGE!"
console.log('INNER');
}
}
}]);
For brevity, I've left some of your lines commented out. I hope this helps.