angularjs scope bindings and rootscope - javascript

I have some elements I want to only show the author of the document.
I can do something like this:
<div ui-show="currentUser == doc.user">Edit</div>
<div ui-show="currentUser == doc.user">Review</div>
Which is fine but because in my production code the ui-show is much longer than this example I don't want to copy and paste it everywhere that I need it.
I want to set a single variable that'll dynamically update as users log in and out or as the document gets updated with new / different users.
<div ui-show="isUser">Edit</div>
<div ui-show="isUser">Review</div>

I found that I could make isUser into a function.
<div ui-show="isUser()">Edit</div>
<div ui-show="isUser()">Review</div>
And write the conditions in the controller.

You have a couple of options to solve this problem:
1) Introduce a "global" or "parent" controller to your application. This will contain your isUser scope variable that you can basically set from any controller beneath this controller. Meaning that you can have a LogInController which will handle log off/in and can set that variable via $scope.isUser = false.
Here is a fiddle with an example of what this might look like: http://jsfiddle.net/digitalzebra/MrQrX/
2) Load different templates or includes based on whether or not the user is logged in/off. when using <ng-include src="partialTemplate"> the src attribute is actually an expression. So, you can toggle what template is actually loaded based on the value of that expression. You can then set the value in your controller and dynamically change which template is loaded: $scope.partialTemplate = "loggedOff.html"

Related

change an angularjs nested template at run time

I have a template which is nested inside another template which I want to load when i click on a button.
So the nested template is loaded dynamically. This is what I have done so far.
This is the main body.html (this loads when a url is provided in the browser e.g. http://url#/newtemplate)
<div ui-view> </div>
Other section of the code has been removed for brevity
This is the new_template.html which I expects it to show when I click a button.
When I put a template name directly like below i.e. when I hard code it
<div ui-view="number1"></div>
It loads the template fully.
This is the dynamic model
<button ng-model="template_name" ng-value="number1">Button1</button>
<div ui-view="{{template_name}}"></div>
{{template_name}}
The above does not load the template as I expected. but it shows the string number1 when
the button is clicked
What can I do for it to load the template....
This is my controller
.state('parent',{
url: '/newtemplate',
views:{
'':{
templateUrl: "parent.tpl",
contoller:"controller",
},
'number1#parent':{
templateUrl:"number1.tpl",
contoller:"formcontroller"
},
'number2#parent':{
templateUrl:"number2.tpl",
contoller:"formcontroller"
},
'number3#parent':{
templateUrl:"number3.tpl",
contoller:"formcontroller"
}
}
})
Strange enough when I used the dot notation it did not work so I have to use the absolute naming method.
I also noticed that when I added the nested views as shown above the time it takes before the template gets loaded take a very long time.
Please I would appreciate any help which can allow me to load a nested view at runtime (possibly very fast)
Expecting more answer
I still hope that the I can make use of ui-view/ui-router because of the ability to make use of controller.
I'm not sure you can use uiView to load html dynamically.
I would try another possible solutions:
Use directives
Using ngInclude
I'll leave you an example with ngInclude: https://next.plnkr.co/edit/M5hl71mXdAGth2TE?open=lib%2Fscript.js&deferRun=1&preview

Angularjs aliasing scopes

I'm stil learning Angular so forgive me if the question is nonsense
I have an object with this hierarchy:
{
a : [...],
b : [{
a: [...]
}, {
...
}]
}
That is I have the same object model for direct children and indirect children of the main object. That is, the two properties named "a" have the same fields
I built a view that is managed with ng-view, and thought that could be called in the main controller and in the ng-repeat that iterates through b elements. However, I don't know how to change the scope that is passed to the view managing "a":
The main view is made in this way:
<div ng-controller="MainController as ctrl">
<div ng-include="'subView'"/>
<div ng-repeat="bElement in ctrl.b">
<div ng-include="'subView'"/>
</div>
</div>
In subView, i can access element like bElement.a because I get the same scope as the outer controller. But how to access property a of the root element?
What I would need, is to have something like ng-repeat that permits to create an alias to a property so that it can be overridden, but without the "repeat".
I tried also using ng-init in this way:
<div ng-controller="MainController as ctrl">
<div ng-include="'subView'" ng-init="list = ctrl.a"/>
<div ng-repeat="bElement in ctrl.b">
<div ng-include="'subView'" ng-init="list = bElement.a"/>
</div>
</div>
but only the second invocation works
Above code should work, but the only thing which I can see here missing is, you haven't closed below ng-include div correctly. So it stops browser will not consider the exact next div & the innner ng-repeat div will not get render.
<div ng-include="'subView'" ng-init="list = ctrl.a"/>
So it should be closed the div correctly, so that the next element on same will taken by browser.
<div ng-include="'subView'" ng-init="list = ctrl.a"></div>
Sample Plunkr of above issue.
Solved working Plunkr list variable updated in child.
Though it will work, I'm seeing some architectural threat in current implementation, because current implementation looks very tightly coupled. Any small change in requirement could lead to re-work on it. As ng-init may harm you in future. If suppose your collection is going to update in specified time of interval(at that ng-init expression will not evaluated on second time rendering of template)

Using the same directive in a directive [angularjs]

I have a need to use the same directive within a directive, depending on a conditional param. However, when ever i try to do it, it seems to go to an endless loop. As i understand, it tries to pre-load the templates and that causes an endless recursion and at the end, it just throws me the following error:"RangeError: Maximum call stack size exceeded".
I have created an example in fiddle.. as you can see in the example, when the param's value is "1", it creates the error (even when the second level param is valued as "2" so it shouldn't have real recursion issues in the controller/app).
https://jsfiddle.net/qh9nh1gx/
"custom-directive"'s template:
<div>
<div ng-if='info==1'><div custom-directive info='2'></div></div>
<div ng-if='info==2'>DONE,single.</div>
</div>
Thanks
I have found 2 options to deal with the issue, the first one, is exactly what Jju described - creating a new "compiler" method (it can be grabbed from the url he sent).
The second option - always using an additional template for the "recursive" parts of the directive. For example, in my directive, i had a "ng-repeat" part that depending on the items value, it could request to display the directive again. while i used "ng-include" to have the other directive, it worked.
<div ng-repeat="item in items" ng-include="'inline-possibly-recursive-template"'></div>
in that template, you can call the directive again without any issues..
I hope that it will anyone else that will stumble into that issue.
You can look into https://stackoverflow.com/a/19065910/1680674 that describe a common approach to create directive that use himself inside

AngularJS ng-include only once

How can I use ng-include in such way that it's content will be loaded only once?
Here is what I have:
<div data-ng-if="%condition-1%" data-ng-include="%url-1%"></div>
<div data-ng-if="%condition-2%" data-ng-include="%url-2%"></div>
<div data-ng-if="%condition-3%" data-ng-include="%url-3%"></div>
...
In my case only one condition is true at some moment of time.
And any condition can change its value many times during page lifetime.
So ng-include will load the same content again and again.
How can I tell Angular to process ng-include only once - when the appropriate condition becomes true for the first time?
Loading them all at once will kill the page because every template is large and heavy.
Also there is no strict sequence of condition changes, for example, condition-3 may never become true during page lifetime - I'd like not to load url-3 content at all in this case.
Thanks!
UPDATE
Yes, template is already on cache. But it has a complicated internal structure like references to external images, iframes and so on - all this things are reloading each time when I'm using ng-include.
You have many solutions but only 2 come to my mind at the moment
1° Replace the ng-if for a ng-show, as the ng-if deletes the dom and all children scopes available, forcing the framework to make the request once again, while if you were using ng-show, the dom would only be hidden and the request would have only be made once.
2° If you do need to use ng-if and the content from the server is static, you could cache it on the javascript layer by manually accesing the $templateCache service provided by angular, or if the content you wish to load is html, you could either use the $templateCache service on the javascript layer or use the ng-template tag to preload that data.
Example:
<script id="url/you/want.html" type="text/ng-template">
<div>I am preloaded dom that responds to the url/you/want.html
requests made by this application
</div>
</script>
Cheers
How about using only one ng-include and using some logic in the controller to switch which source to use using a binding? This way only one will ever be loaded at a time.
Controller
function($scope) {
$scope.activeTemplate = null; //some default or even null
$scope.$watch('condition', function(newvalue) {
//whatever logic you need to switch template
if (newvalue == 'condition1') {
$scope.activeTemplate = '/path/to/condition1.html';
} else if (newvalue == 'condition2') {
$scope.activeTemplate = '/path/to/condition2.html';
} else {
$scope.activeTemplate = '/path/to/default.html';
}
});
}
This way only one template will ever be loaded at a time, and you've reduced the number of bindings from 3 to 1. (however you have added a watch so effectively from 3 to 2 maybe)

AngularJS switch controller based on variable

I want to do something similar to a $routeProvider .when but instead of using URL I would like to load an HTML file and a new controller based on a variable change.
Assume I use a $http polling and the poll has a variable that changes, and I would like to change the Controller and template based on that. What is the best strategy for this
I'm new to this so please excuse if this is a stupid question.
Thank you so much.
The first thing that comes to mind is you could do something like this
<div>
<directive1 ng-if="switch_var == val_1"></directive1>
<directive2 ng-if="switch_var == val_2"></directive2>
...
</div>
Create a directive for each template/controller combo you want, and then choose which directive to show based on your poll variable.
Alternative to using a bunch of ng-if's, use ng-switch - http://docs.angularjs.org/api/ng/directive/ngSwitch

Categories

Resources