Perform custom action after ng-repeat is completed rendering elements - javascript

I need to make a manipulation with DIV element that is a result of ng-repeat:
<div ng-repeat="data in info" >
<div id='plot_{{data.id}}'></div>
</div>
My sequence is as follows:
I add information in $scope.info
ng-repeat happens
after DIV is generated (as you can see, it has also the dynamically assigned ID), I need to call a particular routine to insert a plot into that DIV.
How I can code the step 3 to happen right after ng-repeat rendering happens?

Create a directive to go on your generated div, and insert your plot within the directive.
app.directive('plot', function(){
return function(scope, element, attrs){
//Insert plot here
//Maybe something like: $.plot(element, yourData);
console.log('directive ' + scope.data.id + ' done');
}
});
HTML:
<div ng-repeat="data in info" >
<div id='plot_{{data.id}}' plot></div>
</div>
Demo

Related

How to load controller as per specific condition using Angular.js

I am facing some issue. I have some nested controller within one parent controller and I need it to execute as per some condition using Angular.js. I am explaining my code below.
NABH.html:
<div ng-controller=NABHParentController>
<div ng-show="showNabh">
<div ng-include="'nabh1.html'"></div>
</div>
<div ng-show="showNabh1">
<div ng-include="'nabh2.html'"></div>
</div>
</div>
nabh1.html:
<div class="right_panel" style="display:block;" id="auditnabh" ng-controller="NABHController">
<td class="sticky-cell" ng-click="initiateNABH(nabh.NABHAuditID)">
</td>
</div>
nabh2.html:
<div class="right_panel" ng-controller="NABH2Controller">
<h2 class="page-title">NABH (INT012017001)</h2>
<div>
NABHParentController.js:
var app=angular.module('demo');
app.controller('NABHParentController',function($scope,$http,$state,$window,$location,$filter){
$scope.showNabh=true;
$scope.showNabh1=false;
})
NABHController.js:
var app=angular.module('demo');
app.controller('NABHController',function($scope,$http,$state,$window,$location,$filter,getBothIdToAuditDetailPage)
{
$scope.initiateNABH = function(aid) {
$scope.$parent.$parent.showNabh=false;
$scope.$parent.$parent.showNabh1=true;
}
})
Here Initially all controller are loading and nabh1.html is displaying first. When user will click on that td click event the second part html is showing. Here I need when user will click on that ng-click="initiateNABH(nabh.NABHAuditID)" the second view will open and the resepective controller will start execute. Initially only displaying view related controller will execute. Please help.
It sounds like using ng-if instead of ng-show will solve your problem:
<div ng-if="showNabh">
<div ng-include="'nabh1.html'"></div>
</div>
<div ng-if="showNabh1">
<div ng-include="'nabh2.html'"></div>
</div>
The difference is that while ng-show will "only" hide the element using css when the expression is falsy, ng-if will not create the element if it's falsy and as a result will not initiate the controller until ng-if is truthy.
Also, I would probably move the initiateNABH function to the parent controller - it will still be available in the child controller but makes the code less likely to break since you don't have to use $parent:
var app=angular.module('demo');
app.controller('NABHParentController',function($scope,$http,$state,$window,$location,$filter){
$scope.showNabh=true;
$scope.showNabh1=false;
$scope.initiateNABH = function(aid) {
$scope.showNabh=false;
$scope.showNabh1=true;
}
})

Using ng-click to show divs in Angular js

So I have a link in an html box and when clicking the link iam trying to have it show a whole new set of divs replacing the present divs.
I tried :
<a href="" ng-click="Search('Show Products A B C')" > Show Products </a>
Search calls in the function in the controller which returns the data for the A B C products, which are then displayed using
<div ng-repeat="products in Search( 'Show Products A B C')" </div>
I am basically trying to do something like this:
<div ng-repeat=" href="" ng-click="Search('Show Products A B C')"> </div>
which is not proper syntax I understand.
But right now nothing happens.
Basically from that ng-click i would like to call that portion of the code (ng-repeat) because right now they are not connected.
thanks
ng-repeat will respond to changes in its argument, but your argument is a function Search(). I would suggest the following:
In your search function:
$scope.Search = function(arg) {
// do your search logic
$scope.productList = <search result list>
}
then in html
<div ng-repeat="products in productList" </div>
What you should do is to have some array or object A bound to $scope, then when you call search you update A and the changes will be reflected on your view
$scope.show=true;
$scope.products =[A,B,C];
$scope.Search = function() {
// do list update
$scope.show=false;
$scope.products =[D,E,F] ;
}
You also need to change ng-repeat to this:
<div ng-repeat="product in products" </div>
And add ng-show to the first link:
Click Me
Edit:
Check this fiddle for a working example.
Edit:
Fiddle updated reflecting latest changes.

Is it possible to interpolate an HTML element into the document in AngularJS?

Say in my controller somewhere I have:
$scope.elements = [document.getElementById('a'), document.getElementById('b')];
and I have valid elements somewhere in the document with IDs of a and b.
I'd like to interpolate these elements directly in an HTML template, without writing JavaScript. I tried the following, and it did not work.
<div ng-repeat="e in elements">
{{ e }}
</div>
Is this possible?
More information about what I'm doing:
I have content (several custom directive elements which load up their own data via AJAX) that I want to disperse between several columns. The column of the content elements will change, and the number of columns will change.
<column-resizer options="columnResizerOptions">
<content1></content1>
<content2></content2>
...
</column-resizer>
The template for columnResizer currently looks like this:
<ng-transclude></ng-transclude>
<div ng-repeat="column in columns">
<div ng-repeat="element in column">
{{ element }}
</div>
</div>
columnResizerOptions is information about how to resize the columns and where to place the content in the columns. In the link function for the columnResizer, I use transclude to grab content1-contentn and place them in arrays corresponding to the column they should be in, which I ngRepeat through in my template (above).
Not sure why you wouldn't treat your whole app the "Angular way", but you could write a directive to do this:
angular.module('demoApp', [])
.directive('interpolateHtml', function() {
return {
restrict: 'A',
scope: {
htmlElement: '='
},
link: function postLink(scope, element) {
element.append(scope.htmlElement);
}
}
})
And use it in your HTML like this:
<div ng-repeat="e in elements">
<div interpolate-html html-element="e"></div>
</div>
Here's a working plnkr: http://plnkr.co/edit/5NvMA1x0C8TcwdLO2FNK?p=preview
It is possible.
$scope.elements = [ (document.getElementById('a') || {}).outerHTML ];
and
<div ng-repeat="e in elements">
<div ng-bind-html="e"></div>
</div>
You won't get data binding this way. You can use innerHTML or jqLite html() instead to get rid of extra wrappers.
get them into the DOM without using append, as it would be cleaner.
It wouldn't. A directive with nested directives or with DOM modifications in link is proper way in this case, you don't have to use data binding everywhere just because Angular promotes it.

ng-click requires two clicks for view to update

I called ng-click like this:
<div ng-repeat="(key,value) in filterdata">
<div ng-click="filter(key,value)">
{{key}} ::::::: {{value}}
</div>
</div>
and my Controller function looks like this:
$scope.filter = function(key,value){
$location.search(key, value);
var filter = $location.url();
service.get(filter).success(function(data) {
$scope.applicationdata = data.data;
console.log($scope.applicationdata);
});
}
and my HTML file has ng-repeat like this:
<div class="resultsa" ng-repeat="data in applicationdata">
{{data.name}}<hr>
<div ng-repeat="metadata in data.metadata">
{{metadata.name}} , {{metadata.pivot.value}}
<hr>
</div>
</div>
The first time I click, my service function is called and my model is updated but my view doesn't update. When I click a second time, my view properly updates. Can anyone tell me why this happening?
This is because you are changing the value of the model after the digest cicle was triggered, and in a different context. For solving this you need to call $scope.$apply() after setting the application data, for triggering another digest cycle.

Recursion using Angularjs and Append Elemnts to an HTML Template

I am quite new to Angularjs . I am working on an app which use Angularjs for front end and django-tastypie for back end. What I am doing is i have a topics list where topics are nested in each others as child parents for multiple levels. these levels can be multiple. my data structure is as
[{'id':1,
'name':'science',
'subtopics':[{
'id':1,
'name':'chemistry',
'subtopics':[{'id':1,
'name':'atom',
'subtopics':[{'id':1,'name':'science',:'subtopics':[]]
]]}}
I may have this nested list for multiple levels . What i want to do is that i want to do is that if I select an element from select list which has subtopics, a HTML is appended to the template and selected elements subtopics become its elements . If there is only one level there will be only one select menu on the template.
Tell me how can I represent this tree in Template using angular. or tell if anyone have any better idea.
my desired HTML rendering is like
<label>Topic Level 1:</label>
<select ng-model="qt_topic_level_1" ng-options="topic.name for topic in qt_topicslist_level_1" ng-change="showSecondLevelTopics()">
</select></br>
<label ng-show="secondleveltopicslabel" ng-true-value="true" ng-false-value="false">Topic Level 2:</label>
<select ng-model="qt_topic_level_2" ng-options="topic.name for topic in qt_topicslist_level_2" ng-change="getThirdleveltopics()" ng-show="secondleveltopicslist" ng-true-value="true" ng-false-value="false" >
</select></br>
means if the subtopics are available in the selected topics list a select tag should be appended to the template to select the sub topic and so on. First time I want to show the root elements only. and then on click want to show the subtopics level by level.
You need to split your template in to two. The first one can by used as recursion container, the "main" topics template:
<div ng-repeat="topic in topics">
<div include-tpl="path/to/topic/tpl-recursive"></div>
</div>
And the single topic's template:
<div class="topic">
<!-- ..topic content.. -->
<div class="subtopics">
<div ng-repeat="topic in topic.subtopics">
<div include-tpl="path/to/topic/tpl-recursive"></div>
</div>
</div>
</div>
I use custom include-tpl directive because ngInclude creates new scope (or used to create, I'm currently using a bit dated version of angular):
.directive('includeTpl', ['$compile', '$http', function($compile, $http){
return {
restrict: 'A',
link: function($scope, $element, $attrs) {
var replace = typeof $attrs.replace !== 'undefined';
$scope.$watch($attrs.includeTpl, function(value) {
if (!value) return;
$http.get(value).then(function(html){
var content = $compile(html)($scope);
if (replace) $element.replaceWith(content);
else $element.html(content);
});
});
}
};
}])

Categories