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)
Related
I'm trying to update a custom directive in AngularJS - it currently has a fixed template specified within the code (using the template: attribute).
I'd like to allow the user to optionally provide their own template instead, using the templateUrl: attribute.
My problem is how to provide a fallback - I can't use both template and templateUrl in the same directive. This is required to allow backwards compatibility.
I've tried using a function for templateUrl, but returning HTML isn't a runner there.
Any other suggestions?
If you use function in templateUrl, you are suppose to provide "template identifier" Angular first looks into the template cache, if its not found it tries to do asynchroneous request for the resource of the same url.
So you can simply put your default template into the file and just return its identifier as default.
By the way, if you are using templateUrl and html in separate files, be sure to use some kind of tool like https://www.npmjs.com/package/ng-html2js in the build process.
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.
Till now I am using Angularjs 1.2 normal global controller syntax but now I need to move 1.3 and use the new controller as syntax and avoid global declarations as our requirements.
Now I am in the process of learning it. But some how I am failing to make it work even some simple basic application. Please find my Plunker.
Neither <h2> {{ctrl1.item }}</h2> nor {{$scope.subItem}} from my directive are giving expected output. Can any one help me to fix plunker to out put item and sub item. And also can any provide me some good references to get familiar with this kind of new syntax using 1.3 and example tutorials, etc
In your plunker remove the $curDir
Try using the console in chrome or something next time. Got error:
Error: [$injector:unpr] Unknown provider: $curDirProvider <- $curDir <- mainCtrl
http://plnkr.co/edit/NrThd1?p=preview
As side note: if you see binding expressions {{ }} in your HTML then usually AngularJS has exploded with an error in the console output.
Problems with your directive:
a)
function postLink($scope, $element, $attrs) {
// This is not valid JavaScript
template : '<p> I am from New Directive with Item {{$scope.subItem}}</p>';
}
b) there is no javascript appending that template to the element. So you can't see anything until it does:
$element.append(template);
-- OR --
$element.append(angular.element(template));
c) there is no point using controller and link objects of a directive together - use one or the other is a good start point.
d) if you use controller then inside the directive body use binding expressions {{ }} to display data as you would normally. Also note, if you use controller as, make sure this is in you directive controller object:
function curDirective() {
return {
restrict: 'E',
controller: 'mainCtrl as vm' // <-- see here
};
}
Fixed:
http://plnkr.co/edit/AGB5bp?p=preview
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 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.