while using ui-select, I find it's too complicate to write, so I want to simplify it by creating my own directive. But it doesn't work.
.directive('crmSelect', function($rootScope) {
return {
restrict : 'E',
replace : true,
transclude : true,
scope : true,
template : '<ui-select> </ui-select>'
};
})
And the html is fairly easy:
<crm-select> </crm-select>
while running the code, angular report error (Error: [$compile:multidir] http://errors.angularjs.org/1.4.4/$compile/multidir?p0=crmSelect&p1=%20(mod…3A%20crmui.controllers)&p2=uiSelect&p3=&p4=transclusion&p5=%3Cui-select%3E)
But if I replace the template to be something like template: 'abcde ' , then it works as expected, if I directly use ui-select element in html, it also works correctly.
From the error messages, looks like there is conflict for multiple directives, does anyone knows the root cause and how to fix this?
Thanks a lot.
Following can be the reasons
Multiple directives requesting isolated scope.
Multiple directives declared with the transclusion option.
Multiple directives attempting to define a template or templateURL.
Related
in this plunkr example, I am simply trying to create my own ng-include directive that just replaces the src attribute automatically with something else (add some extra params).
When the 'replace' attribute on the directive is 'true', it breaks with the error above. If I set it to 'false', everything is ok but then I get an extra level of nesting in my DOM, which I'm trying to avoid...
The expression that fails is:
template: '<ng-include src="src | srcizer"></ng-include>'
Is there any way to use replace=true and still create this kind of ng-include alternative?
This should work:
template: '<ng-include ng-src="src | srcizer"></ng-include>'
I don't understand what are you trying but seems you don't need to use ng-include since you can use templateUrl instead of template in directive. This allows to store angular templates like common html in html files.
Here is your updated plunker
Pay attention to templateUrl: 'mytemplate.html' this update in your directive.
And now about replace:true. According to angular documentation its deprecated, so avoid using it.
replace ([DEPRECATED!], will be removed in next major release - i.e. v2.0)
I have an ng-view with multiple instances of the localytics (angular) Chosen plugin. I also have an ng-include with one instance of the plugin. Both rendered on the same page.
I'm using the data-placeholder attribute to render a value which is filtered through the angular-translate plugin.
Initially I was having issues with all Chosen instances rendering the translated text when the method to update the language was being called.
I got around this by calling $route.reload() at the end of the method (not ideal, but acceptable).
I tried:
binding the values for the translations and the translate filter inline
setting them in controllers
watching the properties on the $scope (which never
triggered)
destroying the template before reloading the route
However, the placeholder within the ng-include refuses to update without the use of a hard refresh. Calling $window.location.reload() at the end of the method allows all instances to show the correct translation, but short of this I've not been able to find a way to fix the issue.
I'm assuming it's a scoping issue. Perhaps the Chosen plugin (which is a directive) creates its own scope, then the ng-include has its own scope, as does the ng-view.
All properties that are being translated, outside of the Chosen plugins, are working as expected.
Currently the angular-translate objects look like this:
var translationEN = {
SEARCH: {
'SEARCH-BTN': 'Search'
}
}
So I'm binding them inline as per the following:
<div ng-bind="'SEARCH.SEARCH-BTN' | translate">
I've also attempted some of the methods on $translate, such as $translate.refresh() to no avail.
If anyone has any ideas, any help and / or comments are very much appreciated.
Thanks in advance.
You can use the chosen attribute to pass in some configurations instead of using the data-placeholder attribute, like this:
<select chosen="{'placeholder_text_single': 'Select the options'}"></select>
Or you can write custom attributes that the chosen directive will also accept as configurations. However, when using attributes, the directive will evaluate the expression instead of using the literal value, which won't work as expected for translation purposes, as '{{ ... }}' is not a valid expression. The attributes would be like this:
<select chosen placeholder-text-single="'Select the options'"></select>
A similar problem occurred for me when the options were loaded by a promise.
With just an empty array, the translation worked fine, but putting the promise back in the code caused this behaviour.
A quick debugging in the chosen directive showed that, the element, from which the chosen angular plugin takes the template for the chosen widget, is not linked (or compiled... I'm really new with angular), it still contains the {{placeholder.string | translate}} value for the data-placeholder attribute, however, the attr.placeholder contains the tranlated value.
So this line sets wrong value as the default text: https://github.com/localytics/angular-chosen/blob/master/chosen.js#L57
I extended the chosen directive with a preLink function, which modified the element's data-placeholder attribute with the right value:
angular.module('myModule').directive('chosen', function() {
return {
priority : 1,
restrict: 'A',
link : {
pre : function(scope, element, attr, ngModel) {
var defaultText = attr.placeholder;
angular.element(element[0]).attr('data-placeholder', defaultText);
}
}
}
});
I'm trying to nested some directives on the examples looks like I got everything I need but not work as I expect, but if I put the nested directive out of the parent directive it is recognized
here is a plunker:http://plnkr.co/edit/eZaYTHm274zWx8GPMAS0?p=preview
the main purpose of this nested directives is to share the data between controllers and build a set of fields dynamically.
Thanks in advance!
Resource: https://docs.angularjs.org/guide/directive
You have two problems with your code: the restrict property and the transclude/template properties. See the code excerpt below.
return {
restrict: 'AE', //You need to add "A" if you are using attributes
transclude: true, // You need to include the ng-transclude directive in your template
template: '<div> Some Html <div ng-transclude></div></div>',
...
};
I am trying to build a directive with angular.
Here is the plunker
I wanted to split it into 3 directives:
Top, grand-parent directive. - many DAYS
Middle, created with ng-repeat - one DAY
Bottom, created with ng-repeat - many TIME BLOCKS
angular
.directive('dateTimeBlocks', [function dateTimeBlocksDirective () {}]) .directive('dayBlock', [function dayDirective () {}])
.directive('timeBlock', [function timeBlockDirective () {}])
I wanted to create middle and bottom directives with
isolated scopes and only pass the data that I want to modify inside.
But it seems to unable to compile
"Multiple directives [dateBlock, dateBlock] asking for template on: ..."
Any input would be greatly appreciated.
This line causes that error:
<date-block data-date-block="datePeriod"></date-block>
The reason is a combination of factors. First, AngularJS always normalizes directive declarations, so data-date-block (or x-date-block, data:date:block etc.) is actually treated as date-block. Therefore, the above line is equivalent to:
<date-block date-block="datePeriod"></date-block>
Now, the dateBlock directive is declared with restrict: 'AE', so it can be applied as either an element or attribute. Therefore, the above line resulting in AngularJS applying the dateBlock directive to the element twice.
That per se doesn't cause the error, but dateBlock declares a template and AngularJS doesn't allow an element to have 2 templates (it doesn't make sense anyway, which template should AngularJS choose?), so it throws an error.
There are several ways to fix it.
Restrict the directive to E so that AngularJS doesn't treat data-date-block as a directive.
Rename the isolated scope property dateBlock to something else.
Use the attribute form of the directive and use <div> for the element form. Like this: <div data-date-block="datePeriod"></div>
Just in case anyone else comes here, you can also get this error if you have a template and templateUrl in the same directive.
i.e:
...
template: '<div>Hello world</div>',
templateUrl: "MyTemplate.html",
...
Hope that helps someone, the error message doesn't immediately point you to this.
I'm trying to follow angular best practice recommendation and use directives to
encapsulate reusuable HTML elements.
The error message:
Error: Template must have exactly one root element. was: partials/user/path/to/somedata.html
the directive code:
.directive('stDirectivename', function() {
return {
restrict: 'E',
replace: true,
// transclude: false,
template: 'partials/user/path/to/somedata.html'
};
})
And the template:
<div ng-show="person.condition" class="someclass">
<span class = "personRoi">
<i class="anotherclass " ng-class="{'specialclass1': person.count>=0,'specialclass2':person.count<0}">
</i>{{person.somedata}}%
</span>
</div>
Called in the partial (which is the template of a modal) as:
<st-directivename></st-directivename>
when I replace the template url for a simple html string in the directive. Everything works. Unfortunately I can't do that for the real template that involves both ' and“. besides this solution won't scale to the larger templates I plan to some directives.
Also when I just insert the template html instead of the directive tag, everything works correctly (I'm actually extracting the code from the existing html to make it reusable).
I read in other SO questions that this has to do with having extra space/tags/comments in the template. But I just can't find such elements.
Does anybody know a solution for this? I'll be glad for any help.
your mistake is: you must use templateUrl rather than template so as to indicate the path to the html partial
.directive('stDirectivename', function(){
return {
restrict:'E',
replace:true,
//transclude:false,
templateUrl:'partials/user/path/to/somedata.html'
};
})
For those that may come after, also note that directive templates need to have --as the error says-- only one root element i.e. multiple spans or divs must be enclosed in a root div.
Also note the comments on the OP: Whitespace or trailing comments in the template may result in this error as well.
It appears a fix to make Angular less temperamental about this may be included in the next release/update: github.com/angular/angular.js/issues/1459
For those who are still looking for further clues...I ran into this same error when I had a typo in the templateUrl path of the directive. You get this error if you have replaced: true. Otherwise, you may see more wild error as WARNING: Tried to load angular more than once, which took me quite a while to figure out because the error message is really misleading.