ng-repeat running on state change - javascript

I have a strange issue in angular and ionic. I have the "ifPostExcluded" being called again when exiting to another state.
This is also being called when the repeater has finished loading (notice I have my own directive "on-finish-render") to detect this.
<div ng-repeat="post in postList" on-finish-render="ngRepeatFinished">
<div class="{{post.id}}" ng-if="post.cat.length > 0">
<div class="w-col w-col-4 push-block-wrap" ng-if="ifPostExcluded(post.cat, post.id)">
<div ng-include src="'templates/_loop.html'"></div>
</div>
</div>
I am puzzled as to why this is happening. I found this neat solution but before I implement it I would rather try to solve the issue.

Just for those who are having a similar issue, I solved it by using one time binding as per this post.
AngularJs alternative to ng-if to save digest

Related

Angular JS ng-switch with ng-include?

I have 3 different code fragments which I'd like to swap out depending on the selection in a select menu.
It works if I include the code inline, but when I try to use ng-includes like this, I get an Angular error and the app fails:
<div ng-switch on="pFilter">
<div ng-include="'includes/parcel_details_incoming.html'" ng-switch-when="Incoming Parcels"></div>
<div ng-include="'includes/parcel_details_forward.html'" ng-switch-when="Exception Parcels"></div>
<div ng-include="'includes/parcel_details_exception.html'" ng-switch-default></div>
</div>
What am I doing wrong here? Does ng-switch not work with ng-includes?
The reason is both the directives ng-include and ng-switch-x use transclusion and you are specifying both on the same element and it is not allowed. Move nginclude to the child of ng-switch element.
<div ng-switch on="pFilter">
<div ng-switch-when="Incoming Parcels"><div ng-include="'includes/parcel_details_incoming.html'"></div></div>
<div ng-switch-when="Exception Parcels"><div ng-include="'includes/parcel_details_forward.html'"></div></div>
<div ng-switch-default><div ng-include="'includes/parcel_details_exception.html'"></div></div>
</div>
This used to work until angular 1.x version but compound transclusion will result in multidir error starting 1.2.x version of angular. Take a look at the change log and this commit.

Can I use a JQuery plugin from within an angularjs directive?

I'm quite new to javascript in general. I've spent the past couple of weeks building a front end with Angular.js.
I have a number of directives I've defined that sit on my page, Angular has been great for this.
Here's what my main page looks like:
<body class="body" ng-controller="OverviewController as overview" font-size:1em>
<sidebar-menu ng-controller="PanelController as panel"></sidebar-menu>
<div id="content" >
<div>
<div class="list-group">
<div class="list-group-item" ng-repeat="site in overview.sites" ng-click="">
<div class="item-heading">
<h3>{{site.name}}</h3>
<p>Address: {{site.address}}</p>
Click Here
</div>
<installationsite-panels ng-controller="PanelController as panel"></installationsite-panels>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function(){
$('.paulund_modal').paulund_modal_box();
});
</script>
</body>
Note the javascript function to call a modal box at the bottom, using this tutorial.
I've spent the past few days trying different tutorials to get modals to work in my webapp, but with no success. I think it's down to my lack of understanding of Angular and Javascript in general.
In any case, I've managed to get this tutorial to work using JQuery, and when I click on the link, the modal opens as expected.
However, I don't want to call this modal from here. I want to call it from a directive that's embedded within the <installationsite-panels> directive in the above code, which looks like this (just a single section shown here):
Device Statuses
<div>
<div class="device-icon-group">
<div class="device-type1-icons" ng-click="panel.showDevices(3)" ng-show="showtype1Red"><img src="img/type1red.png" style="width:50%; height:50%;"/></div>
<div class="device-type2-icons" ng-click="panel.showDevices(3)" ng-show="showType2Red"><img src="img/type2red.png" style="width:50%; height:50%;" /></div>
</div>
<div class="service" ng-click="panel.showDevices(3)" ng-show="showService">
<b>{{panel.getServiceDeviceCount()}} device needs servicing</b>
</div>
<div ng-show="showServiceList">
<device-list-service></device-list-service>
</div>
</div>
The directive <device-list-service> shows a list of items like so:
<div ng-controller="DevicesController as deviceList" font-size:1em >
<div id="device-list-group">
<div id="device-list-group-item" ng-click="" ng-repeat="device in deviceList.devicesService">
<div ng-class="device.status"><img src="{{(device.type == 'type1') ? 'img/type1white.png' : 'img/type2white.png'}}"> </div>
<div class="device-params">
<b>ID: </b> {{device.id}}<br />
<b>Type: </b> {{device.type}}
</div>
<div class="device-params">
<b>Location: </b> {{device.location}}<br />
<b>Action: </b> {{device.action}} <br />
</div>
</div>
</div>
</div>
I want to show the modal when the user clicks on one of the list-group-item 's, and display some data relating to that item.
The modal works fine from the top level in the main app, but I cannot call it from within any of the directives. How can I do this?
Is it possible, or do I need to scrap my JQuery modal and do it the Angular way, which hasn't worked for me for the past few attempts.
Don't use jquery modals. You can, but you shouldn't.
Instead, I recommend using Angular UI, which has a pretty usable modal implementation: https://angular-ui.github.io/
Second alternative: if you don't like Angular UI, then use AngularJS + Bootstrap, and create your own custom directives
Third alternative: Use jQuery.
If you still want to go with the 3rd alternative, despite my advice against it, then here is how you do it:
var app = angular.module('app', []);
app.directive('modal', function($http, $timeout) {
return {
restrict: 'A',
link: function(scope, element, attr) {
$timeout(function() {
element.paulund_modal_box();
}, 0, false);
}
};
});
Usage:
<div modal></div>
Some explanation is needed here.
Why is the $timeout service necessary? jQuery plugins often require the DOM to be fully loaded in order to work properly. That is why most jQuery plugins are wrapped inside of a $(document).ready block. In AngularJS there is no concept of DOM ready, and there is no easy way in AngularJS to hook into the event. However, there is a well-known hack, which is to use the $timeout service. In Angular there are three phases:
1. compile - Angular walks the DOM tree looking for directives
2. Link - Angular calls the link function for each directive to setup watch handlers.
3. Render - Angular updates the views
Using $timeout within the Link function queues the $timeout function to be executed until after the current closure is done executing. It just so happens that the Render phase is within the current closure's scope of execution. Hence, the $timeout function will execute after the render phase, when the DOM has been loaded.
Mixing JQuery and Angular in that way is maybe a little messy, but sometimes you do want to use a well-built component. You could try to find a similar modal in Angular - angular-modal - or you could try and build the component into your Angular directive itself - jQuery Plugins in AngularJS

In AngularJS 1.2, how do I specify the controller for an ng-include?

We are attempting to upgrade from AngularJS 1.0.7 to 1.2.1. In 1.0.7, we were able to set the controller for an ng-include alongside in the same element, like so
<div data-ng-include="'include1.html'" data-ng-controller="MyCtrl1"
MyCtrl1 would become available to the code inside include1.html.
This breaks when moving to AngularJS 1.2.1 which I have illustrated in this plunkr. If you change the referenced version to 1.0.7 it works again.
I am interested in understanding what has changed/why this is. I tried searching but couldn't find anything or I am not using the right terms.
Additionally, what would be the correct way to specify a controller for my ng-includes?
Why not move the ng-controller from the element having ng-include to inside the template:
index.html:
<div data-ng-include="'include1.html'"></div>
<div data-ng-include="'include2.html'"></div>
include1.html
<div data-ng-controller="MyCtrl1">
<h1>{{Username}}</h1>
</div>
include2.html
<div data-ng-controller="MyCtrl2">
<h1>{{Username}}</h1>
</div>
It seems ngController and ngInclude cannot be used in conjunction with each other since Angular version 1.2:
Issue 1, Issue 2, Issue 3 and SO post.

AngularJS 1.2 ngInclude inside ngIf

I'm running into some odd behavior when putting an ngInclude inside an ngIf or ngSwitch.
For example, take the following:
<button ng-click="showIncTemplate = !showIncTemplate">Toggle Included Template</button>
<button ng-click="showInlineTemplate = !showInlineTemplate">Toggle Inline Template</button>
<div ng-if="showIncTemplate">
<p>Included template:</p>
<div ng-include="'template.html'"></div>
</div>
<div ng-if="showInlineTemplate">
<h1>Inline Template</h1>
</div>
(http://plnkr.co/edit/gULbwnKb0gQS8DWz0V6U)
The buttons toggle an options to render the divs that follow. The inline example behaves as expected, with the content appearing or disappearing on click.
The div with the child include seems not to include the template when first drawn, but then includes it repeatedly on every subsequent redraw.
What's going on here? I do see some breaking changes around ngInclude, is there some other way I should be doing this? Or is this a bug in Angular?
Edit:
It looks like this is already in the angularjs github issue tracker:
https://github.com/angular/angular.js/issues/3627
They've fixed it in this snapshot:
http://code.angularjs.org/snapshot/

viewContentLoaded - Without duplicating code per each controller - AngularJS

Hey all I'm trying to get a feel for angular and have ran into a little snag.
I have a container structure like the following:
<div class="main-container" ng-view>
<!-- The below divs are constantly being
reloaded based on the current URL and it's associated view -->
<div class="left-col">
</div>
<div class="right-col">
</div>
</div>
Before I implemented Angular I just had a simple script that would check the height of the window and set the height of the left column and right column divs accordingly.
With angular there is probably a better way to do this then attaching an event function to the window object. Basically I want to fire a function everytime a new view is rendered but not duplicate the below code in all of my angular controllers like so:
$scope.$on('$viewContentLoaded', setColumnHeight);
Any help would be appreciated. Thanks!
I've solved this problem in my app by having a root "Application Controller" at the top of the DOM tree. For example:
<body ng-controller='applicationController'>
...
<div class="ng-view"></div>
...
</body>
applicationController is always there, and can set up bindings on its scope when it is created.
How about putting that event listener on the root scope:
$rootScope.$on('$viewContentLoaded', setColumnHeight);
You could use something like this:
<div class="main-container" ng-view>
{{ setColumnHeight() }}
<!-- The below divs are constantly being
reloaded based on the current URL and it's associated view -->
<div class="left-col">
</div>
<div class="right-col">
</div>
</div>
and it will check the height every time a render is made, however, this seems to be a bit over processing.
The best approach would be to only update the height from both columns when the height of one of them changes. For that you could use DOM Mutation Observers, however they are not yet available on all browsers. If that's not a problem for you, check the mutation-summary lib.
If you are using jQuery you can also try this: https://github.com/jqui-dot-net/jQuery-mutate (examples here).

Categories

Resources