$viewContentLoaded isn't firing - javascript

$viewContentLoaded never fires in my Angular controller. The following:
function MyController($scope)
{
$scope.$on('$viewContentLoaded', function()
{
alert("blah");
});
}
Never hits a breakpoint, and never pops up the alert. I think this is pretty standard use, so I'm not sure what it could be, but it's definitely not firing. Everything else in the controller is behaving properly.
What would cause this?

Try this instead:
function MyController($scope)
{
$scope.$watch('$viewContentLoaded', function()
{
alert("blah");
});
}

Base on your comment above, it sounds like you have something like this:
<ng-view>
<div ng-controller="MyController"></div>
</ng-view>
I'm not sure what content in the ng-view tag will do, but the $viewContentLoaded is emitted from the ng-view scope. This means, it only goes up from the ng-view and thus your controller would never catch it.

I solved this by specifying the controller in the app.js route provider rather than using ng-controller in a div in the view. I only use this method if I need to use $viewContentLoaded, otherwise I use ng-controller.
angular.module('myapp', [...])
.config(function ($routeProvider, $locationProvider) {
$routeProvider
.when('/MyRoute', {templateUrl: 'views/MyView.html', controller: MyController})
});

Related

Waypoints.js not working as expected with angular views

I am trying to apply some css animation to some of the elements in my views when they reach the top of the window (offset 70%) with the help of waypoints.js.
I've created a directive as shown below.
angular.module("myApp")
.directive("clWaypoints",function(){
return{
restrict:"A",
link: function(scope,element,attrs)
{
var wayp=new Waypoint({
element:element,
handler:function(direction){
if(direction=="down")
{
var animation = scope.$eval(attrs.clWaypoints).animation;
element.css('opacity', '1');
element.addClass("animated " + animation);
}
},
offset:'70%',
})
}
}
})
Below is my app.js file
angular
.module('myApp', [
'ngRoute',
])
.config(function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/home.html',
controller: "mainCtrl"
})
.when('/about', {
templateUrl: 'views/about.html'
})
.otherwise({
redirectTo: '/'
});
});
Both the views contain elements which use the cl-waypoints="{animation:'fadeInUp'}" directive.
When the app is loaded on a browser, the animations work as expected, but when I navigate to another view and begin to scroll down the elements in that view are not animated. Anyhow if I refresh the page, it works just fine.
Looks like the page needs to be refreshed for waypoint.js to do its magic. Please let me know if there is a solution to this problem.
Would appreciate any help.
Thanks.
Was able to find a solution to this problem. Waypoint requires us to call a function (Waypoint.refreshAll()) every time we make changes to the DOM, in our case changing the view content.
Added an $viewContentLoaded event listener (in the parent controller) to call the method whenever the view changes.
$scope.$on('$viewContentLoaded', function(event){
$timeout(function() {
Waypoint.refreshAll()
},0);
});
Hope this helps others.

Autoscroll to TOP with ui-router and Angularjs

I've read so many different problems with this and none of the solution given seem to fit my use case. I started by simply putting target="_top" on all my links, but that actually forces my app to reload which wont work. I've also seen people say they use autoscroll="true" but that only seems to work if its within my ui-view.
The issue with this is that in my index.html file I have fixed nav and other static elements that are above my first ui-view. This means when I go to other pages I lose the navigation as the page loads past those elements. I've also tried putting this on the body with:
<body autoscroll="true">
</body>
This doesn't seem to do anything either. So the question is, how can I make sure that new pages (new route changes from ui-router) result in starting at the top of the page? THANKS!
If you want it to always scroll to 0 cross-browser, do nothing with autoscroll. Just place this your run block:
$rootScope.$on('$stateChangeSuccess', function() {
document.body.scrollTop = document.documentElement.scrollTop = 0;
});
Using version 1.0.6, the $stateChangeSuccess event is deprecated in favor of the $transitions service. Here is the code I used to scroll to the top on every state change:
app.run(['$transitions', function ($transitions) {
$transitions.onSuccess({}, function () {
document.body.scrollTop = document.documentElement.scrollTop = 0;
})
}]);
I had exactly the same problem, fixed navbar on route changes, page loading partially scrolled down the page.
I just added autoscroll="false" to ui-view, like so:
<div ui-view="main" autoscroll="false"></div>
edit
Just tested this method, bit of a dirty hack, but it works. Import angular services $anchorScroll & $location into the relevant controllers for ui-router .state config. Then use a $watch on ui-router $stateParams to call $location.hash('top'); on route/state changes.
https://docs.angularjs.org/api/ng/service/$anchorScroll
https://docs.angularjs.org/api/ng/service/$location#hash
.controller('myCtrl', function ($location, $anchorScroll, $scope, $stateParams) {
$scope.$watchCollection('$stateParams', function() {
$location.hash('top');
$anchorScroll();
});
});
There is an Angular service for this.
https://docs.angularjs.org/api/ng/service/$anchorScroll
Sample Code:
.run(function ($rootScope, $state, $stateParams, $anchorScroll) {
$rootScope.$on('$stateChangeStart', function () {
$anchorScroll();
});
});
If you want to scroll to a specific element
.run(function ($rootScope, $state, $stateParams, $anchorScroll) {
$rootScope.$on('$stateChangeStart', function () {
// set the location.hash to the id of
// the element you wish to scroll to.
$location.hash('bottom');
// call $anchorScroll()
$anchorScroll();
});
});
I am using ui-router. My run looked like this:
.run(function($rootScope, $state, $stateParams){
$rootScope.$state = $state;
$rootScope.$stateParams = $stateParams;
$rootScope.$on('$stateChangeSuccess', function() {
document.body.scrollTop = document.documentElement.scrollTop = 0;
});
})
I had to do a combination of the other two answers.
<div ui-view autoscroll="false"></div>
In combination with
$rootScope.$on('$stateChangeSuccess', function() {
document.body.scrollTop = 0;
document.documentElement.scrollTop = 0;
});
Note: This is on v0.2.15 of ui-router
Did the same thing as the excepted answer from #TaylorMac but in $locationChangeStart.
index.run.js:
$rootScope.$on('$locationChangeStart', function() {
document.body.scrollTop = document.documentElement.scrollTop = 0;
});

Angular-ngRoute: force ng-view contents, allow navigation afterwards

While using ngRoute, I want to have Angular configured so that the current contents of ng-view are left as the contents for the current route, and allow the user to navigate away to different routes, rendering their respective templates afterwards:
Plunker
HTML
<ul class="menu">
<li>view1</li>
<li>view2</li>
</ul>
<div ng-view>
<ul>
<li>Some</li>
<li>Soon obliterated</li>
<li>Content</li>
</ul>
</div>
JavaScript
angular.module('myApp', ['ngRoute'])
.config(function($routeProvider) {
$routeProvider
.when('/view1', {
templateUrl: 'view1.html',
controller: 'View1Ctrl'
})
.when('/view2', {
templateUrl: 'view2.html',
controller: 'View2Ctrl'
})
.otherwise({
redirectTo: '/view1'
})
})
.controller('View1Ctrl', function() {
})
.controller('View2Ctrl', function() {
});
When the user first sees the page, I want him to see the following:
Note: Angular needs to be bootstrapped at this point, with directives functioning in this area.
Note 2: This content should be in the actual HTML of the page, not in a template or script tag.
Then, when the 'view2' link is clicked:
And then, when the 'view1' link is clicked:
My first thought was using $route.updateParams(newParams) but I think that's not really its purpose.
EDIT
I ended up using
//Server-side rendered code
myModule
.config(['$routeProvider', function($routeProvider){
$routeProvider.when('<# my current route #>',
{
templateUrl: '/server-static',
});
angular.bootstrap(myModule);
In app.js:
myModule
.config('$routeProvider', function($routeProvider){
$routeProvider.when('/my-client-routes',
{
templateUrl: '/my-template.html',
}); // etc.
How can I trick Angular into thinking that the contents of ng-view are the appropiate contents for the current entry route? Can I just cancel route resolution/ngView directive (or make it transclude) rendering for first load? Or if not possible, what's the preferred method to do this?
Thanks
EDIT: See this answer that proposes adding the contents of ng-view to $templateCache through a custom directive.
It's possible for templateUrl to be a function. In which case you can actually change the view based on some kind of state:
var initialized = false;
$routeProvider
.when('/view1', {
templateUrl: function(){
if(initialized){
return 'view1.html';
}
initialized = true;
return 'view-initial.html';
},
controller: 'View1Ctrl'
})
Here is a working Plunker based on yours.
The task you're asking help for can be achieved in a number of ways. #Josh offers a good one. Using $templateCache is another option. But, as you correctly said, these are tricks.
Correct and only recommended approach is to use dedicated template for a default route. You can specify it via external file, via template cache or even script tag, but it's much better, clear and easy to support.
If it's your own code - just choose any preferred way you like. If you want it to be shared with community, used as open-source or enterprise solution - I'd suggest to use the only recommended approach.
Or... look into ui-router )) . May be it's nested views support is the option you need.

Link to #ID element from another page in AngularJS

I've tried all the solutions presented here:
How to handle anchor hash linking in AngularJS
But none worked for me.
In my header.html I have a link: <a id="button" href="#/views/home#page"> Contact</a></li>
To an ID in home.html
When I am in /home it works, but when I am in another page it doesn't work.
I tried using ##page with no success.
Or putting this in app.js:
app.run(function($rootScope, $location, $anchorScroll, $routeParams) {
$rootScope.$on('$routeChangeSuccess', function(newRoute, oldRoute) {
$location.hash($routeParams.scrollTo);
$anchorScroll();
});
});
and customizing my link:
href="#/views/home/?scrollTo=page"
Can someone explain which files should I edit and how?
Edit:
I started from Angular-Seed
My app.js is:
'use strict';
// Declare app level module which depends on views, and components
angular.module('myApp', [
'ngRoute',
'myApp.view1',
'myApp.view2',
'myApp.training',
'myApp.faq',
'myApp.media',
'myApp.contact',
'myApp.home',
'myApp.apply',
'myApp.classes',
'myApp.version'
]).
config(['$routeProvider', function($routeProvider) {
$routeProvider.otherwise({redirectTo: '/views/home'});
}]);
And in every view I have another js file like training.js which looks like:
'use strict';
angular.module('myApp.training', ['ngRoute'])
.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/views/training', {
templateUrl: 'views/training/training.html',
controller: 'TrainingCtrl'
});
}])
.controller('TrainingCtrl', [function() {
}]);
It is configured based on angular-seed model.
So, when, I am in view /faq that has the partial header with the menu and all the links, how can I link to a specific ID in view /home?
I think that the problem is that you have the logic for scrolling to that hash in the $routeChangeSuccess and as the documentation says, this event is:
Broadcasted after a route dependencies are resolved. ngView listens
for the directive to instantiate the controller and render the view.
So the view is not rendered yet, therefore the DOM element with that id doesn't exist yet.
Try putting that logic in the onload event of the ngView directive instead.
I've created this plunker: http://plnkr.co/edit/S7bUT8iYY7UEti71X5Z8?p=preview that shows that if you add that logic into the onload event of the ngView directive everything works fine.

Run javascript code after angularjs route loaded

I need to show an alert after a route has been loaded by angularjs. The piece of code to show the alert is in the view loaded asynchronously by angularjs:
<script>
alert('test');
</script>
Once the view has loaded, I expect this to be run, but it does not. I know I can broadcast and tell it to run afterwards etc, but I need a more generic solution.
Assuming you are talking about route changes based upon ngRoute internal to an angular SPA
Inject $route into your controller:
.controller('MyCtrl', function($scope, $route){});
and in your controller you subscribe to the event of the route changing:
$scope.$on('$routeChangeSuccess', function() {
alert('test'); // <-- alert from the question
});
There is one more option to run javascript function use ngInit
<div ng-init="initialize()"></div>
call the function which is inside the controller
app.controller('myController', function($scope){
$scope.initialize = function () {
alert("Page loading just completed");
}
});

Categories

Resources