I have a constant app.constant('DOCUMENT_ID', window.documentId || 1); which I inject into services, controllers and directives.
I want to change DOCUMENT_ID to be a global variable, so that if I change DOCUMENT_ID's value in controller, I want to get the changed value in all services and controllers in which DOCUMENT_ID was injected.
How can I use a global variable in this way?
You don't need global variable here (plus it's a bad practice). Just make use of the fact that objects are passed by references. For example you could use a service defined like this:
app.value('DOCUMENT', {
ID: window.documentId || 1
});
Now, whenever you change DOCUMENT.ID anywhere, every part of the application will have updated version of ID. Just read it like object property.
Demo: http://plnkr.co/edit/Oay8IaLRnuCN2xkSuM69?p=preview
Related
So I have a dust.js helper which requires some jsx module when called and afterwards renders this module as html (some kind of plugin).
{#react type="Text"\}
...
<some Markup>
...
{#react type="Text"\}
{#react type="Text"\}
Meanwhile I have a data structure which contains all the elements that should be rendered on this template (a page)
['1st', '2nd', '3rd']
In my helper I'd like to know how often I called #react. Like incrementing a counter on the context which all helpers called within this template can access.
I was fiddeling around with context.pop() and context.push but wasn't able to mutate the template's context. Every helper gets it's own. So I either need a way to get the call count of the helper or store the current number of invocations of the helper somewhere accessible to the other ones.
However, when doing sth like {#react type="Text" index=0\} and afterwards accessing it with context.get(['page', 'elements', params.index]) it works (of course). But this enforces me to keep count of the elements I am disposing (especially annoying when adding and removing elements)
Hope s/o has an idea, maybe I'm just missing sth really simple.
Cheers.
There is a special global object attached to each Context that contains references you'd like to be available everywhere in your template.
For more information, see Context Globals.
You prepopulate the global by calling dust.context({ foo: 'bar' }) to create a Context object. You can pass this to Dust in your render step instead of a plain Object.
Inside any helper, you can access the global directly to set properties on it:
react: function(chunk, context, bodies, params) {
var numTimesCalled = ++context.global.numTimesCalled;
});
You can use properties in the global in your template. You can think of them as being at the "lowest" level in the context stack.
In the following plunk:
http://plnkr.co/edit/ss3HTb?p=info
I am attempting to bind an attribute to an isolate scope. However, it is not working. I'm wondering if anyone knows why that is?
I've looked through several resources, including:
Need some examples of binding attributes in custom AngularJS tags and http://www.sitepoint.com/practical-guide-angularjs-directives-part-two/
You specified the isolate scope as
scope: {
attr: "=attributeName"
}
What that does is take the value of attributeName specified in your html as an expression in your scope and bind that to attr in your directive scope. But what you did was just to specify "hello" without having a hello object in your scope. To get it to work the way you have it now, you have to use the # attribute binding like so:
scope: {
attr: "#attributeName"
}
The other change that you need to do is how you specify the value in the html. You use titleCase when you define the attribute, but in the html instead of titleCase you need to seperate the "words" by a dash and use all lowercase. So attributeName becomes attribute-name
<node attribute-name="hello"></node>
On the other hand, if you actually want to bind to the value of an object in your scope, then make sure that you specify it in your scope and then you can use it in your directive (and preferably use the dot notation).
I have you updated your plunker to show you how they work.
I have a problem when creating multiple directives with isolated scope: when I change something in 1st directive it also makes changes in all other directives.
Here is a working example: http://plnkr.co/edit/drBghqHHx2qz20fT91mi?p=preview
(try to add more of Type1 'Available notifications' - a change in 1st will reflect in all other directives of Type1)
I found some solutions to similar problems here but they don't work in my case. Also found a working solution with mapping 'subscription' data to local scope variables in directive (app.js, line 76) but I think there should be a more general way to do this right?
In your directive 'notificationitem' you have the following code, keep it in mind as i explan:
// if all variables are mapped in this way than works
//$scope.enabled = $scope.subscription.enabled;
The reason why all of the 'isolated' scopes are updating is because of this code in your scope declaration in the same directive (notificationitem):
scope: {
subscription: '=',
index: '#'
},
The equal sign on subscription is angular's way of saying "Whenever the current scope updates, go to the parent and update that value as well." This means whenever you update your 'isolated' scope, it updates the parent scope as well. Since all of these isolated scopes are binding to the parent, they will change as well.
Since you want the subscription.value to be the default value of that text field, you will need to do exactly what your commented code is doing:
scope.value = scope.subscription.value;
This will create an isolated value inside of the isolated scope. When scope.value changes, scope.subscription.value will not. All of the text fields now have their own 'value' to keep track of.
Check out this article for information on directive bindings: http://www.ng-newsletter.com/posts/directives.html
Also, another way to get the default value would be to inject your service into the directive, if you don't like the above solution. Hope this all helps.
I've got a hbs template where I've got an array of objects and a boolean toggle variable (toggles the template behavior), let's say:
{
objs: list,
mode: true
}
I'm not able to access the mode variable when inside the loop over objs (the context is changed). What I want is to make an if-statement using the upper variable. I found that I can write a custom helper. But is there no other way to access the variable? I also found out, that inside the loop the variable is accessible via {{../mode}} - but still, don't know how to access that.
Finally, I've found a solution:
{{#if ../mode}}xyz{{/if}}
I'm trying to create a custom component that receives arguments in a ng-repeat loop.
So for example, say I have a component named "mycomp" that receives a custom argument "name" in a ng-repeat:
<mycomp name="{obj.name}" ng-repeat="obj in list" />
And in my directive the isolated scope is defined like this:
scope:{name:"#"}
That won't work because ng-repeat creates an isolated scope for each element it iterates. So I ended up having two levels of scopes.
How do I get around this issue? Am I doing something wrong?
Thanks.
As I stated in my comment of your original question, this has already been answered. Anyway, here it is, summed up:
In your template, state the model you want to have inherited, without {{}} (as using brackets results in the value being passed, and not the reference to the model itself):
<mycomp name="obj.name" ng-repeat="obj in list" />
And in your directive, establish a 2-way binding, like so:
scope:{name:"="}
EDIT:
I realize now (after your comment) that while this solves your problem, it doesn't fully answer the question. Here goes:
When you create a directive you have the choice of creating a scope that inherits from its parent (controller, typically, though not necessarily) ou an "isolated" scope, by specifying scope: true or scope: {...}, respectively.
So, by creating an unisolated scope, all the parent's models are available (you can access scope.obj - created via ng-repeat - but also scope.list). This is convenient, but also dangerous, of course (and doesn't really create reusable code).
If you create an isolated scope, you can specify the scope's models using '#', '=' or '&'.
'#' and '&' both produce a isolated, unbinded value, (that, if you change, changes only on the isolated scope - in your case, the object in the original list suffers no change at all), the only difference being that '#' reads a string value, and '&' reads an expression.
THIS IS IMPORTANT: the reason why I believe your code didn't work was (only) because you passed name="{obj.name}" and not name="{{obj.name}}", for with '#' the string value is read, and that string value can be the name of obj, but you must include it in {{}}!
If you use '=', you are declaring that you want that variable to be binded with the specified outside variable. So, if (in a fit of crazy, crazy rage!) you want to have 2 models in your directive that start up with the same value, but on is binded (i.e. changes are propagated to the outside scope), you could do something like this:
<mycomp binded-name="obj.name" unbinded-name="{{obj.name}}" ng-repeat="obj in list" />
and in your directive:
scope:{
bindedName: "=",
unbindedName: "#"
}