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

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.

Related

Why wont ngRoute now work and breaks all other Angular functionality?

I am trying to us ngRoute to inject HTML into my web page but it doesn't work.
I have the below in my main html document.
<main ng-view></main>
next i created a folder call views with two HTML files (news.html & sectors.html)
I have also included angular-route.min.js into my project correctly. All paths for all files are correct.
Next I set up my routes as below, but it renders a blank page and even breaks the rendering of any ng-includes I have implemented which previously worked. In addition, it also breaks all other Angular functionality like filtering. There are no errors in the console, it just seems that ngRoute wont work.
var app = angular.module('app', ['ngRoute']);
app.config(['$routeProvider', function($routeProvider){
$routeProvider
.when('/sectors', {
templateUrl: 'views/sectors.html'
})
.when('/news', {
templateUrl: 'views/news.html',
controller: 'primaryController'
}).otherwise({
redirectTo: '/sectors'
});
}]);
Any help welcome.
You can check templateUrl for the path to your html templates. Everything else seems correct.

angularjs ui-router persistant page elements

I am trying to get my head around angularjs and ui-router at the moment, my application is split into 3 layouts basically (Marketing Layout, Authentication Layout & Application Layout). I am currently struggling to get my ui-router working to allow me to do this, I understand that I can have parent states that are abstracted (correct?) but I am struggline to get child states to inherit parent views etc.
Basically what I wanting to do is the following - I'll use the application section of the site for the example.
A user is logged in logged, and the screen is split into a header, sidebar, and main content area, where the ever the user goes within applicaiton section of the site, the header and sidebar will remain but the main contnet will update to the relevant content. Here is what I have so far
app.config(['$stateProvider', '$urlRouterProvider', '$locationProvider', '$httpProvider', function($stateProvider, $urlRouterProvider, $locationProvider, $httpProvider){
$urlRouterProvider.otherwise('/application/dashboard');
$stateProvider
.state('application', {
abstract : true,
views : {
'#' : {
templateUrl : 'templates/layout.html',
controller : 'applicationController'
},
'top#index' : {
templateUrl : 'templates/app/header.html'
},
'left#index' : {
templateUrl : 'templates/app/sidebar.html'
},
'main#index' : {
templateUrl : 'templates/app/main.html'
}
}
})
.state('application.dashboard', {
url : '/application/dashboard',
views : {
'#' : {
templateUrl : 'templates/schools/manage.html',
controller : ''
},
'main#app' : {
templateUrl : ''
}
}
})
}]);
https://plnkr.co/edit/6fJNjTFhoKqyN82P7NvL?p=preview
As you will able to see I can see the manage.html template, but on the preview I should also see the page header from the header.html template, and the sidebar.html also...
Any ideas as to why I am not? I assume it is something I am doing wrong.
If I understand what you're saying, you basically want an app skeleton of Header, Sidebar and MainContent. The only thing that should change is MainContent. The contents of the header or sidebar may change, but they'll be persistent.
I personally think router should have nothing to do with this; a router should route. Having it be a data bus and application state manager seems to tightly couple things that shouldn't be.
Anyway, with that said, here's how I go about it. In my index.html, here's my markup:
<body ng-app="app">
<div header-directive></div>
<div ng-view></div>
<div footer-directive></div>
</body>
That's it. If you have other elements and need them to be responsive, just use a bootstrap grid (like to lay in sidebars or whatever). If you don't have to worry about any of that, a good ol' simple html table does the job perfectly. You can use CSS to do fixed positioning, height, etc.
With this setup, your header and footer never go away, and the router will only change the content in the ng-view. You use the router for the one and only thing that the term "router" makes sense for: routing from here, to there. Here's a sample router config:
.config(['$routeProvider', ...
function ( $routeProvider, ... ) {
$routeProvider.
when('/home', {
templateUrl: 'views/home.html',
controller: 'HomeController',
controllerAs: 'homeCtl'
})
.when('/info', {
templateUrl: 'views/info.html',
controller: 'InfoController',
controllerAs: 'infoCtl'
})
....
For communication between the three components, you can just create a service that they all inject. This way you can send any one of the elements (or all of them) instructions to change their content, hide/show themselves, whatever you need.
Angular does sometimes drastically overcomplicate something simple. This is definitely one of them. The Router in Angular 2 is a complicated behemoth.

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.

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.

reload state when you are on same state in angular ui-router

My Question is can we reload the view in ui-router if you are on same state.
check my code at`http://plnkr.co/edit/MA7CuyH2RFrlaoAgBYog?p=preview
My app.js file is
var app = angular.module('plunker', ['ui.router']);
app.config(function($stateProvider) {
$stateProvider
.state("view1", {
url: "/view1",
templateUrl: "x.html"
})
.state("view2", {
url: "/view2",
templateUrl: "y.html"
})
})
app.controller("MainCtrl",function(){});
And index page is
<body ng-controller="MainCtrl">
Accounts
Dashboard
<div ui-view></div>
Now click on Dashboard link here you will see a text box. fill any value in that. Now again click on Dashboard link. now the state should reload and all data of page should be reloaded including its controller. Please make sure to ui-router only.
Thanks
add attribute to the element with
ui-sref=""ui-sref-opts="{reload:true}"
example:
<a ui-sref-opts="{reload:true}" ui-sref="app.post.applicants">Applicants</a>
Use ng-click and write a controller function with $state.go
You could catch the click in a "ng-click" and use the $state service to transition/reload pragmatically
I had this similar issue and I solved this in two simple way ...
First I wrote a function into related controller (my state was 'inbox' you can use your own ui-state):
$scope.reload = function() {
$state.go('inbox', null, { reload: true });
}
Second call this function to anchor tag:
<a ng-click="reload()">Inbox</a>
Hope it will help. :)

Categories

Resources