A better alternative to ng-switch? - javascript

I'm trying to dynamically load a directive template based on a condition, in my case the type attribute from directive scope. The template that is being loaded looks like this:
<div ng-switch="type">
<div ng-switch-when="player" ...></div>
<div ng-switch-when="npc" ...></div>
</div>
After reading some related questions, I have found that there is a way that I can do what ng-switch does, but within the directive itself. I have tried to use vanilla JS switch inside a function that replaced the template string within the directive, but with no success, my guess would be due to the fact that I was using a scope attribute as the switch condition.
Being new to Angular makes finding and understanding solutions to my problem quite difficult, so if I didnt explain my issue with enough clarity, let me know.
Any help is greatly appreciated.

Related

AngularJS ng-bind-html and components

I'm using AngularJS ver. 1.6.8.
I have a component I have built called icons. To incorporate it in a page I just add <icons></icons> and the component is inserted into the page.
Now I have a scope variable that holds html, and part of that html is the previously mentioned code <icons></icons>.
When I use ng-bind-html it doesn't compile the component and instead just shows <icons></icons> as text.
I have tried using angular-bind-html-compile (link) but that didn't help.
All of the solutions I found seem to support angular pre made directives and not newly formed components.
Happy to hear of any possible solutions.
Did you do the following on your scope variable which holds the html code? This is a common mistake.
$scope.trustAsHtml('<div>....')
But as mentioned before, without your code it is hard to figure out the problem.

ng-show does not work correctly with ng-animate

When animate module is loaded then ng-show does not work. Default value for ng-show expression is false, but element is still shown and class ng-hide is missing. If i unload animate module, then it works fine.
<script>
var app=angular.module('app', ['ngRoute','ngCookies','infinite-scroll','ui.mask','ngAnimate']);
</script>
I have the same problem, it's probably a timing issue, but there is a workaround.
in short, there is some collision between a class defined in the "class" attribute with interpolation, and other directives on the same element trying to add another class. removing the class="{{::item.customClass}}" gets ng-class and ng-show directives to work fine.
I couldn't reproduce it on a plunker, probably because of the large amount of components involved. we use $templateCache service, ngAnimate module, and a directive that uses ng-repeat with dynamic class and ng-show (and more, which did not seem to affect the problem). Removing any of those mentioned had solved the issue.
there is one thing I didn't try and that's trying to detach the code from the ui-view hierarchy, perhaps the ui-router is a part of the problem.
Debugging showed that after the ng-class/ng-show's watch executes, the right class was added and it looked like this: class="{{::item.customClass}} ng-hide", but at the end of the digest cycle it looked like this: class="myCustomClass". I guess that is what happens in your code as well.
The way I handled this situation is by moving item.customClass to the ng-class like so: ng-class=[{ ... other classes}, item.customClass]
it's a workaround and not a real solution because:
it's probably a real issue inside Angular's code.
I don't know how to use bind once here, and it's important of course.
Take a look at animate.css. It works with Angular and you can trigger it by class='ng-show'.
Like this:
<div class="animated fadeInRight" data-ng-class="loginShow">
If you set $scope.loginShow to 'ng-show' in your controller it will trigger the animate effect automatically.
If you want to trigger the animate effect on 'ng-hide' you have to write it in your controller like this:
$scope.loginShow = 'ng-hide-add animated fadeOutRight';
Hope this helps!

Angularjs directive dependencies (order of execution)

Let's say I have the following html in which masterdir and innerdir are custom directives:
<div master-dir>
<div inner-dir ng-repeat="x in set"></div>
</div>
How can I make the directives execute in the following order (without using $timeout, 'cause it looks ugly to me):
ng-repeat
n times innerdir
masterdir
Background: I want to alter the dom in every directive and the directives kind of depend on each other (the innerdir should alter the dom that ng-repeat produces and the masterdir should alter the dom produced by innerdir)
I've tried it with priority, require and pre/post/compile but I didn't find the right mix. I'm really out of ideas at this point.
In https://docs.angularjs.org/guide/compiler they say that, but none chart is there. Anyway, I found that in each directive docs page, in Directive Info section, the priority appears wrote like that (for ng-repeat):
ng-repeat:
Directive Info
This directive creates new scope.
This directive executes at priority level 1000.
I also found the next link that seems to be very helpful. I´m still reading it trying to learn (didn´t know too much about angular priorities). Hope this is helpful for you too.
http://www.bennadel.com/blog/2447-exploring-directive-controllers-compiling-linking-and-priority-in-angularjs.htm

Initialize AngularJS Model From HTML Tag

I'm working with django + angular. I'd like django to populate a value in the HTML template, and then tell Angular to use that value as initial value for a model.
I need this for two reasons:
Simplicity - The page deos not currently use Angular, and I believe
it would be
easier to upgrade this way.
SEO - Some search engines can't read
values populated in the DOM through Angular. I know there are
several solutions for SEO with Angular but I hope there's an easier
way?
Any help would be greatly appreciated :)
You can initialize you model based on that initial HTMl value.
For instance your HTML would be:
<div ng-bind="value">initialValue</div>
And you controller:
var elem = $( 'get the element' );
$scope.value = elem.text();
Angular will then take over and can reflect any change made to $scope.value.
The downside is that you need to grab the element (using jQuery here for simplicity but you can use vanilla Javascript).
One way to work around that would be a custom directive:
<div late-binding="value">initialValue</div>
I let the directive code as an exercice to the reader, unless you need help for it :)

Custom widgets in AngularJS

I have a list of HTML widgets which are created dynamically from server data like this (Jade):
.area(ng-repeat="widget in widgetsList.widgets")
h3 {{widget.title}}
p {{widget.type}}
span {{widget.data}}
Widgets are not of the same structure and I don't want to show them visually equal because each of them represents its own functionality. The paragraph in the end of the example just puts data json as a string that I obviously need to render as a proper html widget according to its type that looks like 'important-messages-widget' or 'recent-events-widget'.
Angular looks pretty good but lacks of detailed documentation. How should I manage this case?
In Angular there are two built in directives that are really what makes angular soo powerful.
ng-repeat ( which you are already using)
ng-switch
This seems to be most often misunderstood or not understood or something to that effect by most developers. It gives you the power of a switch statement in your normal programming language in html.
http://docs.angularjs.org/api/ng.directive:ngSwitch
The doc's for it should provide you a good starting point. Combining ngSwitch with ng-repeat will give you a very powerful way of representing your view.
<div ng-switch on="widget.type" >
<div ng-switch-when="important-messages-widget">Important Message</div>
<div ng-switch-when="recent-events-widget">Recent Events ---add more html here </div>
</div>
Hope this helps.

Categories