For a partial view I want to do some JavaScript stuff that I usually would do with $(document).ready(function() {...})
, e.g. bind venet listeners to elements. I know that this doesn't work for AngularJS and partial views loaded into the "root" view.
Thus I added a listener to the controller that listens to the $viewContentLoaded
event. The listener's function is invoked, so the event is fired but it seems to me as if it is before the partial view is rendered. Neither do I see the elements when I set a breakpoint in the listener's function and debug it with firebug, nor does the jquery selection within the function find the partial view's elements.
This is what the controller looks like:
angular.module('docinvoiceClientAngularjsApp') .controller('LoginController', function ($scope, $rootScope) { $scope.$on('$viewContentLoaded', function(event) { console.log("content loaded"); console.log($("#loginForm")); // breakpoint here }); [...]
I guess that I am doing something wrong as there had to be more posts on stackoverflow if this is a common bug.
As I am using ui-router and ui-view, I will give you an excerpt of the routing file:
angular .module('docinvoiceClientAngularjsApp', [ 'ui.router', 'ngAnimate', 'ngCookies', 'ngResource', 'ngMessages', 'ngRoute', 'ngSanitize', 'ngTouch' ]) .config(function ($routeProvider, $stateProvider) { $stateProvider .state('login', { url: '/', templateUrl: 'components/login/loginView.html', controller: 'LoginController' }) .run(['$state', function ($state) { $state.transitionTo('login'); }]) [...]
Any help is appreciated. Thanks and kind regards
UPDATE 1: I stripped the error down to the following usecase: The loginView.html looks like the following:
<div id="loginContainer" style="width: 300px"> <form id="loginForm" ng-submit="login(credentials)" ng-if="session.token == undefined"> [...]
As soon as I remove the ng-if
from the div tag, it works as expected. The event is triggered after the DOM is rendered, thus jQuery finds the element. If the ng-if
is attached to the div tag, the behaviour is as first described.
UPDATE 2: As promised I added a working demo that shows the different behaviour when adding a ng-if
directive. Can anyone point me the right direction? Don't stick to the login form as such, as there are many more use cases where I want to remove certain parts of a view based on some expression and do some JavaScript stuff after the partial view is ready.
You can find the working demo here: Demo
This is related to angular digest cycle, it's about how angular works underneath the hood, data binding etc. There are great tutorials explaining this.
To solve your problem, use $timeout, it will make the code execute on the next cycle, whem the ng-if was already parsed:
app.controller('LoginController', function ($scope, $timeout) { $scope.$on('$viewContentLoaded', function(event) { $timeout(function() { $scope.formData.value = document.getElementById("loginForm").id; },0); }); });
Fixed demo here: http://codepen.io/anon/pen/JoYPdv
But I strongly advise you to use directives do any DOM manipulation, the controller isn't for that. Here is a example of how do this: Easy dom manipulation in AngularJS - click a button, then set focus to an input element
I have solved this issue with the help of Directives. Add one direcitve to your element (like <div my-dir></div>
) and do manipulations to the element in respective directive as follows,
app.directive('myDir', function () { return { restrict: 'A', link: function (scope, element) { // Do manipulations here with the help of element parameter } }; });
I have also tried state provider events like $stateChangeSuccess
, $viewContentLoaded
but couldn't solve the issue. Because after those events got fired, it's taking time to render on the DOM.
So, we can follow this approach which gives perfect results and proper way to implement in Angular JS :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With