I'am new to Angular.js, and I am trying to use different templates inside a directive for different clients.
The problem is, I have three templates for three kinds of clients, and I want to use different templates for my directive based on the result of client type after detection
The results I found after Googling was all about adding attributes to the directory tag, but by the time I have detection result ready, the template is already compiled.
Any suggestions?
You could inject a variable into your directive to look in a different directory for the template.
myApp.directive('testDirective', [
'clientType', function(clientType) {
return {
...
templateUrl: '/templates/' + clientType + '/test.html'
};
}
]);
Then you can set the constant 'clientType' outside of your app and pass it in as a constant.
myApp.constant('clientType', 'mobile'); // Some type of function to determine this
You may need to manually bootstrap your app in order to use this effectively though. I am doing something similar in production code to control where templates are loaded from.
You could use ngSwitch within your directive template.
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.
I would like to have few global variables that are UI related (i.e. open menu state). I decided to put these in $rootScope so they're always accessible.
This is the code I've written:
(function (angular) {
angular
.module("App", [])
.run(["$rootScope", function ($rootScope) {
angular.extend($rootScope, {
ui: {
menu: false,
...
}
});
}]);
})(angular);
I've deliberately used angular.extend, to make sure that consecutive manipulations to the same object are retained. And I think it's also more clean and safe than adding several properties to any object one by one.
Problem
Upper code doesn't do anything though. When I run my application and check root scope by calling:
$("body").scope().$root.ui
I get undefined until some property within ui gets manipulated by ng-click directives on my application. Only then my ui gets a reference... But it's still not the one I've defined in the run() function but rather angular generated object property that ng-click directive generated as per expression.
What am I doing wrong?
Resolved - module got overwritten
Ia managed to resolve it myself. Code contained in the upper question isn't sufficient to show the actual problem in my application. The problem was the way I was loading module requirements and file ordering.
I'm loading files in this order:
app.js
routing.js
service.something.js
...
filter.something.js
...
So I thought to add module requirements to my app module in subsequent files (make ti actually modularized). This would make it simple to either include or exclude particular files without any runtime errors. It would also allow loading additional files dynamically as application runs.
The problem with my code was that I've overridden my original module in subsequent files. When I added all module requirements into app.js everything everything started working.
Possible workaround
I can see that I'm not the only person that would like this kind of functionality. Lasy module requirements loading is possible as per this Google groups' post.
What it does is it creates a new injector function
instanceInjector.loadNewModules = function (mods) {
forEach(loadModules(mods), function(fn) { instanceInjector.invoke(fn || noop); });
};
that can later be used by individual modules to add themselves as requirement to the main application module by doing this:
$injector.loadNewModules(["Module1", "Module2", ...]);
Although it would be much better (my opinion) if there was an additional function on Module type called requires() so one could do this instead:
angular.module("MainModule").requires(["AdditionalModule", "OtherModule", ...]);
I think that would make it more concise and easy to use and understand.
I have a page with 2 containers on it , each one contains images. I want to add some specific visual attributes and functionalities to these images. These specific stuff is similar in both depositories but it is not the same. So i want to create one directive for 2 types of images , but i want it to behaviour a little bit differently depending on in what depository ( actually, scope ) image is placed. Checking for element's scope in directive's body:
studio.directive('orientable', function () {
return {
link: function(scope, element, attrs) {
if(scope.id=="Depository1"){
// give to element some specific behaviour
}else if(scope.id=="Depository2"){
// give to element another specific behaviour
}
}
}
seems ugly to me.
I can't use passing arguments to a directive, because then image's tag will turn to unreadable and when there are many images it will be disaster . I do not want two directives because they will be basically same.
So i want one directive , but somehow it must be "polymorphic".
Is it some kind of inheritance possible here? I think i'm missing something important in understanding of Angular' directives .
If you want a single directive to behave differently based on scope, then checking some scope property seems perfectly reasonable to me.
The closest I think you can come to polymorphism in Angular is to put shared things (data, functions, etc.) into a service, then inject that service into the places you want polymorphism (directives, controllers, other services, etc.).
I have a directive which creates a rich text editor in its LinkingFunction. The small directive I'm using for my rich text editor can be found at https://github.com/angular-ui/ui-tinymce/blob/master/src/tinymce.js.
I need to extend this directive with another directive which will allow me to configure the default options and access the element created by the previous directive.
If possible, I would like to do this without forking the original ui-tinymce directive (linked to above). In this directive there are two properties:
uiTinymceConfig which I need to be able to access and configure before this directive's LinkingFunction is run (before the options are passed to TinyMCE)
tinyInstance which I need to manipulate after it has been created by this directive
I've done plenty of research into extending directives, as well as the different attributes available to the "Directive Definition Object", such as link, pre-link, post-link, compile, and controller. I have experimented with sharing properties between two directives using some of these methods, but I have not come up with a solution that fits my needs (above).
I am happy to fork this original directive code if it is not possible to achieve what is needed without doing so.
So I investigated this a little for you, and came up with this Plnkr.
This will let you override the value provided for injection - note that you can do this in a module that depends on the submodule, so you can provide different configurations for different modules that depend on the submodule, which would be of use for the ui-tinymce directive.
Using a similar principle, you should be able to edit the config value for uiTinymceConfig by just simply overriding it. You can even do this and override it right in the base module if you'd like.
If you want to edit the instance itself after instantiation, you can simply access it by using the ID attribute and calling tinymce.get('#IDattribute') directly anywhere in your code.
Say I want to create 'desktop-only' and 'mobile-only' directives that hide or show an element based on and env test. There are a dozen ways I could go about it, but a cool one would be to "partially apply" the existing 'ng-show' directive. So 'desktop-only' would be the equivalent of, and actually delegate to, 'ng-show="env.isDesktop"' but without the need to do the env test in some parent controller and put env in my scope.
Another common example would be a tabs plugin. I could write a tab directive to show and hide elements using show and hide jQuery functions, but this would lose a lot of the functionality already in the ngShow directive. Couldn't I have my tab directive extend the ngShow directive in order to get access to all that variable parsing, integration with ngAnimate, etc...
Is this possible?
Thanks
When using isolate scopes you could manually proxy some variables into the scope: $scope.current.device = $rootScope.current.device;
Appart from that, you could use the afforementioned approach to put a device model on $rootScope and have methods and fields, such as 'hasTouch' that did calls to Modernizr and similar.
So yes, this is possible.