Evaluate AngularJS expression within Material Design Lite's mdl-menu - angularjs

I am building a tiny single-page-application using Angular for the functionality and mdl for the design. I wanted to have a dropdown select box and since mdl doesn't provide this out of the box I built one using mdl-menu. The problem is now that Angular seems to have troubles evaluating expressions I put inside this menu, maybe because the menu is only opened when you click the button? I tried using expressions within the list items and this gives the expression output but also the original expression, which I obviously don't want. I also tried to ng-repeat the list items and then they just don't show up.
<button id="demo-menu-lower-left"
class="mdl-button mdl-js-button mdl-button--icon">
<i class="material-icons">more_vert</i>
</button>
<ul class="mdl-menu mdl-menu--bottom-left mdl-js-menu mdl-js-ripple-effect"
for="demo-menu-lower-left">
<li class="mdl-menu__item">{{5+5}}</li>
<li class="mdl-menu__item mdl-menu__item--full-bleed-divider">Another Action</li>
<li disabled class="mdl-menu__item">Disabled Action</li>
<li class="mdl-menu__item">Yet Another Action</li>
</ul>
Result pic (Look at the evaluation in the top left, but the original expression is the actual "clickable" action)
Thx in advance!

MDL's javascript (denoted by the mdl-js CSS classes) will probably fool around with the HTML before Angular can do anything, eventually creating HTML that gives strange results when 'parsed' by Angular. It would be best to ensure your HTML gets processed in a strict order: Angular first, MDL second.
If you need to work with the HTML after the initial loading and rendering of the page, it would help to inspect the HTML in the browser instead of relying on the source HTML. Any javascript code (including Angular) will have to work with this and not the HTML represented by the source.

Related

Have my code act as a p tag and not as a link if there is no URL

I am relatively new to angularJs so I am trying to learn how to do different things. I have been trying to make solutionName act as a p tag if there is no URL input for solutionUrl1, at the moment solutionName is acting as if it is hyperlinked even when its not. Any help would be appreciated.
<a ng-href="{{::data.solutionUrl1}}" class="card__title" style="text-align: center">
<span>{{::data.solutionName}}</span>
</a>
Use ng-if of angularjs to render either one or the other:
Something like this, you most probably have to change the condition to meet your needs. You can also create a new Variable in the JS files like showLink and set this variable to true/false depending on some conditions. And then just use this boolean variable to show/hide the link with the method outlined below:
<div ng-if="data.solutionUrl1">
<!-- code to render the link-->
</div>
<div ng-if="!data.solutionUrl1">
<!-- code to render just the span without the link -->
</div>

Angular Tree Directive with Lazy Loading

We are kicking a new project using angularJS :) and one of the requirements is a tree control.
The tree control should support "Lazy Loading", So we could add nodes to it dynamically as we get more data using AJAX.
I saw the 2 directives below, but I do not think "Lazy Loading" is supported
so before I start developing it myself I am asking you folks :)
The 2 nice tree directives I saw:
https://github.com/eu81273/angular.treeview/blob/master/angular.treeview.js
https://github.com/nickperkinslondon/angular-bootstrap-nav-tree
Thanks, Avi
Because AngularJS loads directives before any logic, you cannot use them very well for recursive operations, else you probably wouldn't need a directive for one in the first place.
However, one very pleasant workaround is using ng-include, as this doesn't have the above limitation. And then making a tree is extremely simple.
Where you want to tree, you have something like
<ul class="tree-container">
<li style="margin: 5px; list-style: none;" ng-repeat="d in vm.features" ng-include="'tree_item_renderer.html'"></li>
</ul>
then the include looks something like this
<script type="text/ng-template" id="tree_item_renderer.html">
<span ng-click="d.expand = !d.expand;vm.getChildNodes(d)" ng-show="!d.expand && d.hasChildren"><i class="fa fa-fw fa-plus-circle"></i></span>
<span ng-show="d.expand && d.hasChildren" ng-click="d.expand = !d.expand;d.children=null" ><i class="fa fa-fw fa-minus-circle"></i></span>
<span ng-show="!d.hasChildren" style="margin-left:28px"></span>
<ul>
<li style="list-style:none;" ng-repeat="d in d.children" ng-model="d" ng-include="'tree_item_renderer.html'"></li>
</ul>
</script>
In the controller vm.getChildNodes(d) call you can get the children for the currently expanded node. I expand the nodes and then actually asynchronously do a count for each node over odata to determine if the node has children, so I can show if one of the children has children of its own, but of course you could more efficiently track that in the database if you have control over that (I think I will update my model for this myself).
Note that I've implemented it so that if you open and close and then open, it actually reloads the nodes. You don't have to do that of course, but it saves me from having to implement a reload/refresh button otherwise and it's not like users are going to open/close trees over and over because they have nothing better to do. ;)
The added advantage I have is that I implement user input for some (most) of the nodes, e.g. select them, enter a value for them. I've noticed it is more efficient if these only exist 'on demand' in angular.

angular js error- 10 $digest() iterations reached. with angular ui Drop down

I am using angular ui drop down element
<div class="dropdown" >
<a ng-click="getTypes();" dropdown-toggle> Add a Type</a>
<ul class="dropdown-menu">
<li ng-repeat="type in Types"><a><b>{{type.sType }}:</b><em>{{type.sDescription}}</em></a> </li>
</ul>
</div>
all that i do is call a web service and populate Types all works fine! But when i add the above code in my htm the div below it starts throwing the exception of max digest reached.
the div below the drop down code(as written above) simply consists of few editable segments with icons and their visibility is controlled by ng-show and ng-hide when the use click a button
say on click of 1st segment i set a variable to true by using ng-click and depending on this variable i show or hide segments by using ng-show and ng-hide
so my doubt is that without the drop down code written above my ng-show and ng-hide work completely fine but the moment i try to use the drop down directive of angular ui i start getting this exception when i click on the buttons . please help.
Edit below is the code which follows basically user clicks on icons to reorder the elements that are appearing in the ng-repeat list and from the drop down which is above the user can add elements to this list
<ul class="repeatList text-center">
<li ng-repeat="widgets in leftWidgets" widget widgets="widgets"
class="wArea">
<a href="" class="icon-remove-circle pull-right" ng-show="editMode" ng-click="deleteWidget(leftWidgets);"
title="Delete Widget">
</a>
<a href="" class="icon-chevron-up slideUpIcon" ng-click="shiftUp(widgets,leftWidgets);"
ng-show="editMode">
</a >
<a href="" class="icon-chevron-down slideDownIcon" ng-click="shiftDown(widgets,leftWidgets);"
ng-show="editMode">
</a>
</li>
</ul>
kept doing hit and trial and found that using empty anchor tags was causing the problem. i.e. i had attached ng-click events to
text //empty href
the moment i changed them to span all worked fine! dont know why the empty "a" tags caused the problem but it will be great if any one can shed some light on the reasons for the above run time angular js exception. the link below is a useful
How to Troubleshoot Angular "10 $digest() iterations reached" Error
thanks!

How to kill image flash in AngularJS

I'm trying to use AngularJS built-in directives to achieve some simple JS effect without writing actual js code. It actually works pretty well, except the initial flash.
I know to deal with text, people should use ng-bind instead of {{}}
But how do you deal with directives like ng-if?
Here is my code:
<li ng-if="!magazines.resolved"> <!-- add "&& isOwner" when done -->
<dl>
<dt ng-model="changeToActivation" ng-init="changeToActivation=false" ng-mouseover="changeToActivation=true" ng-mouseleave="changeToActivation=false"><img ng-if="!changeToActivation" ng-src="<?php echo base_url('public/images/system_icons/add_magazine.jpg');?>">
<img ng-click="addMagazine()" id="activated" ng-if="changeToActivation" ng-src="<?php echo base_url('public/images/system_icons/add_magazine_activated.jpg');?>"></dt>
<dd class="magazineName">Create <br> A new magazine</dd>
<dd class="publishDate">Now!</dd>
</dl>
</li>
I know it gets a bit hard to read, but it's very easy. There is a model defined on <dt></dt> tag. If mouse is over this tag, the model value becomes true; when leaves, it becomes false.
Based on this boolean model value, one or the other image will be shown.
It works like a charm, but I can see both images at the very beginning, flashing!
How to deal with something like this then?
ngCloak may help, but you should also use ng-src for the actual image source, this will prevent your site from loading the image before the model has received a value. Also when using ngCloak, you may need to load the AngularJS source at the top of your html file as it may try to load the image before it knows what to do with the ng-cloak directive.
Applying ngCloak to you dt should do the trick for you: http://docs.angularjs.org/api/ng.directive:ngCloak
Here's an example from the docs. Note that it's added in two places- the directive as well as a class. The class is only needed for IE7 support.
<div id="template2" ng-cloak class="ng-cloak">{{ 'hello IE7' }}</div>

correct strategy to generate html dynamically with angular

I have a huge JSON object tree with two levels. First level has around 500 elements, and each element contains an average of 100 child elements.
I want to display the first level of the tree and I am doing it with a simple ng-repeat. When the user clicks on the element I want to display the child elements of that element. If I use a span ng-switch or a ng-show to show/hide child elements when the page first renders it freezes for around 10 seconds while generating all the HTML.
It doesn't sound like the right solution. There must be a different way of doing it, but I can't figure out. Anyone knows?
I have explained most in my comment, and here is a working plunker:
http://plunker.co/edit/RSZwfLlsCJ68MUkACbdp?p=preview
the new ng-if directive will do what you want
<h1>ng-if</h1> <h5>Click on the level to expand</h5>
<div class="well">
<ul class="nav nav-list" ng-repeat="(attr,element) in tree">
<li ng-click="expand=!expand" ng-class="{'active':expand}"><a>{{element.name}}</a></li>
<ul ng-if="expand" class="nav nav-list">
<li ng-repeat="item in element.items">{{item.name}}</li>
</ul>
</ul>
</div>
you can also do this in the "old-way" with ng-show using new ternary operator or its alternative expr && if_true || if_false
<h1>old-way</h1> <h5>Click on the level to expand</h5>
<small>use ternary operator or <pre>expand && element.items || []</pre></small>
<div class="well">
<ul class="nav nav-list" ng-repeat="(attr,element) in tree">
<li ng-click="expand=!expand" ng-class="{'active':expand}"><a>{{element.name}}</a></li>
<ul ng-show="expand" class="nav nav-list">
<li ng-repeat="item in (expand ? element.items : [])">{{item.name}}</li>
<!--<li ng-repeat="item in (expand && element.items || [])">{{item.name}}</li>-->
</ul>
</ul>
</div>
See this answer on ng-repeat performance. Essentially, it just takes a long time since Angular's ng-repeat, and basically all other directives, are set up to always look for updates in the whole JSON structure. So if you have lots of data and don't need live updates in the HTML view when changing the JSON, I wouldn't recommend using AngularJS. Generally, AngularJS performance also depends a lot on the browser and its JavaScript engine.
Alternatively, you could divide your JSON into subparts and then use pagination to display it.
I would recommend to fetch the data gradually from the server. Use server-side pagination and retrieve only the fields that you are going to display. Then, when a user clicks on one of the first level items, you can do another XHR to the server with the new data. I had similar requirements for a project and that solved the latency issue.
Regards,
Agustin.

Resources