Create an angularjs directive that accepts default settings - angularjs

I would like to create a directive that could be initialized with some default settings when the app is initializing (not when added to a page).
Then when used in a page this directive would use these settings (if they were set) to override its internal defaults.
Saying this in a different way, I want to be able to set properties on a directive in the application level, to avoid setting them on each instance

One option I found to do this, is to create a new directive, wrapping the one in question. In this new directive we will get the global app setting, and provide it to the internal directive.
In this way we can avoid providing the setting value in each page the directive is used in.

Related

Restoring Custom Directives that Manipulate the DOM

I have two custom element directives:
<my-directive-parent></my-directive-parent> //only one
and
<my-directive-child></my-directive-child> //variable count
The my-directive-parent directive has its own controller and templateUrl properties defined in its directive definition object. The my-directive-child directive has its own link, scope, templateUrl and require properties defined in its directive definition object. The fourth parameter passed into the link function is the parent my-directive-parent's controller. This is working as expected.
Based on user input, instances of my-directive-child are appended to or removed from the parent my-directive-parent DOM via the my-directive-parent's controller. Since I'm using ngView for the top-level page, changing pages results in Angular automatically cleaning up the various directives and their controllers of the top-level page. Upon returning, the controller for the page re-runs, but the user appended views do not show up (since they were previously wiped out automatically by Angular). I'm using a service which holds the data representing the collection of my-directive-child instances that were previously added.
My issue lies in restoring the my-directive-child directives based on this cached service data. Currently, when the my-directive-parent directive's controller is run, I'm getting the service data array that represents the instances to be added, looping through it, and adding a new my-directive-child instance to the DOM. This is working, but upon restoring each instance I need to pre-populate it with data that was previously entered by the user (of which is recorded in the service). Currently, when adding to the DOM this way each instance is in a "blank" state instead of a desired pre-populated state.
So I have the data needed to recreate the child directive instances, but I'm unable to pre-populate them with the necessary data.
I've tried to place a custom attr on the my-directive-child in an effort to forward the data to the instance's scope, but I learned from Angular's API docs that:
The new scope rule does not apply for the root of the template since the root of the template always gets a new scope
Questions:
Is my approach wrong? What should I be doing?
Is there a way to pass attrs defined on the actual element directive into the directive's scope that represents the inner template HTML?
How do I ensure a custom directive within a custom directive properly pre-populates itself?
Thank you in advance for any ideas, answers, or thoughts that might lead to a solid solution.

pass parameter to Angular directive template function post-post-link, using $scope, GET or whatever

I am trying to write a directive that will format content for modal display (using Bootstrap classes) if given a certain parameter, and as standard view if not. I have this working for a view loaded directly, toggling on a URL param (?modal) available to $routeParams and/or $location.
I want to use this toggle-able template as a "pipe" for other templates. However, the intended content URL will never be the visible URL when used as a modal. I can't get it working when loading the view with $modal.open or ngInclude, because $routeParams/$location has data for the including page, not the included one.
I put this in a Plunker, but because Plunker also doesn't provide the URL param, the modal view isn't available.
Does Angular provide a means to change the template or templateUrl much later in the process? For example, could I use $scope, either from a controller or on the directive, itself?
Clarification: The goal here is to have one template/partial for each component, with that template used either as a standalone or a modal, based on some switch. The _modal and _alone partials in the Plunker convert the component template into the desired state.
$modal.open takes a single object parameter one of the properties of this config parameter is templateUrl
http://angular-ui.github.io/bootstrap/
So you can create the config object and open the modal with any template you need.
Dan Wahlin uses this technique for a dialog service and then in this article goes on to demonstrate a full modal service
http://weblogs.asp.net/dwahlin/building-an-angularjs-modal-service
There were a couple of issues with your code:
First of all the use $routeParams if you don't use ngRoute's $routeProvider.
In your case, it might be easier to use $window.location.search (and compare it against ?modal).
That said, in order to properly display a Bootstrap modal, you need Bootstrap's JS file (which in turn requires jQuery) and you also need to create the modal (e.g. by calling $('.modal').modal()).
Take a look at this modified demo.
For better intergration with Angular's components, you might want to look into UI Bootstrap.

Extending directives in AngularJS (sharing properties before and after link)

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.

AngularJS - Unwatching auto bound values within curly braces

Is there a built-in method to AngularJS to remove the automatically created watch on a value inserted into a template via curly braces.
For example:
<span>{{someVal}}</span>
In my case, someVal is never going to be changed after it's loaded the first time. I don't need the watch code listening for changes. I'm trying to speed up a page's performance that has a rather large table - some values the user can edit but most are read-only values.
I'm not setting up a watch manually so I don't have a reference to the deregistration method for each value. Do I need to write a custom directive to achieve this?
A buddy of mine found this set of directives for this exact purpose.
https://github.com/abourget/abourget-angular
I have recently found a better way of doing it as it's built in the angular:
<span>{{::someVal}}</span>
More information here: https://docs.angularjs.org/guide/expression

Partially apply an AngularJS directive

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.

Resources