Angularjs - using $routing - when I manually put "#/section/ + myId" , it resets my page - angularjs

So I am trying to implement routing in my app. Here is a sample jsFiddle of what I am trying to do: http://jsfiddle.net/GeorgiAngelov/9yN3Z/114/
So far everything is working fine and as I am moving through the sections, my routing changes and everything is fine.
The problem is the following: when I manually type the section id in my url bar like this my local host : /section/s-3 I get redirected to s-1 and my page refreshes and I loose all of the sections and roots I have added so far. Sometimes it works, and I can switch between sections like that, but sometimes it refreshes, and it happens when I click enter twice.
It's an odd problem and I am not certain on how can I debug it. This is my actuall routing service.
app.config(function ($routeProvider) {
$routeProvider
.when('/', {
redirectTo: '/section/1',
templateUrl: '/tpl.html',
})
.when('/section/:sectionId', {
templateUrl: '/tpl.html',
})
.otherwise({
redirectTo: '/'
});
});

I tested your app on chrome and on firefox. Using chrome, if you select the url and type enter (without changing it) it reloads the page, so hitting enter twice will always refresh the page. Using firefox, this does not happen, so apparently you don't have this problem on FF (although the user can press the refresh button directly).
If you refresh the page, you obviously lose what you have inserted. You need to persist the information you want to preserve between refreshes. If you don't want to send this to your server, an alternative is to use html5 local storage. You can see an example here:
http://todomvc.com/architecture-examples/angularjs/#/

I'we watched your application and from my point of view you're using an odd way to add DOM object to your view, kinda like jquery templating.
Actually each times you click inside a section you're using a different scope and adding a root in a scope it's not visible to the others: instead you should use a service shared between the controllers, this way only the service contains all the sections and all the roots: angularjs services
Later I'will update your jsfiddle, hope this helps for now.

Related

angularjs ui-router: redirect vs multiple url for same state

When I navigate first to my index page where the url is '/', I want to display the content of the state '/matches'. What you think is better?
I can use
$urlRouterProvider.otherwise('/matches');
that works, but I know it's not a good solution.
So I have to choose between
1- redirecting / to /matches and I tried
$urlRouterProvider.when('/','/matches');
but it didn't work.
2- specify multiple paths / and /matches to the same state matches which I don't know how to do.
In ng-route I used to do it like this:
.when('/', {
redirectTo : '/matches'
})
but I don't think it's good to combine ng-route with ui-router.
I found a perfect solution
app.run(function($state){
$state.go('/matches');
});
Once the app runs, I call the state that I want to load using $state.go and I also kept the
$urlRouterProvider.otherwise('/matches');
in case the user tries to enter an invalid url (state), he will be redirected to the initial state.

Angular js - echoing data across multiple html pages

I've worked with many languages and environments (predominately iOS & C#) and have always managed to avoid working with scripting languages. That avoidance streak has come to an abrupt end: as a huge angularjs project was thrown in my lap - now I'm scrambling to understand this very strange world. Some features are really cool, other techniques have me thoroughly baffled. I've spent weeks reading tutorials, studying examples and I still cannot solve a relatively simple problem regarding best practices and structure of the code.
This is what I need to do: I have a form, where the user will input data (for argument's sake, its two fields of number type.) I need to have a banner at the top of the page with the sum of the two input fields - that by itself is relatively easy - but the problem for me, is repeating this banner on subsequent pages.
Home page will contain links to:
page 1
page 2
The link to page 2 will not be available until the user inputs data on page 1, forcing the user to visit page 1, first. The banner element needs to be a separate file. Page 2 is a passive display of the data, Page 1 is only page that can actively edit the data.
page 1: would look like this --
banner.html (sum of fields A & field B)
input field A
input field B
page 2:
banner.html (sum of field A & field B)
Lorem Ipsum ....
What's the best way to achieve this task?
You can have an index page with the banner on top, and partials using the same controller. The value of the banner will be a controller variable.
To use partials, inside the index page, you'll need to include the ngRoute module, and the script tag linking to it.
You'll have a div like this.
<div ng-view=""></div>
You'll have a partialRoutes.js file looking something like this.
myApp.config(function($routeProvider){
$routeProvider
.when('/',{
templateUrl: './partials/things.html'
})
.when('/stuff',{
templateUrl: './partials/stuff.html'
})
.when('/otherstuff',{
templateUrl: './partials/otherstuff.html'
})
.otherwise({
redirectTo: '/',
})
});
When you include ngRoute it will look something like this.
var myApp = angular.module('myApp', ['ngRoute']);
Here are the docs for ngRoute. Hope I helped.
https://docs.angularjs.org/api/ngRoute
Personally, I would have a service, lets call it userData. Your inputController would then write the details of the inputs to the userData service.
Your bannerController would then be notified of changes to the data in the userData service (via $watch or $broadcast)
This way when you switch pages the bannerController should not change and will still display this information
Notes:
This relies on you using some kind of AngularJS routing technique such as NGroute or UI Router. If a hard page navigation is made then the userData will have to be stored server side.
It would probably be better for the banner to stay outside any ui-view so that it is unaffected by navigation, but if it is then as the userData service will still be alive and holding the correct data when it is recreated it will have access to the same data
If both pages have same controller, then $scope can be used to achieve this. If pages have different controller, $rootScope can be used to share variables.

UI Router event on navigate to self page

I'm using ui-router for my page routing in my AngularJS app. I'm encountering an issue where if I click a hyperlink on a page that refers to the page/route I'm already on (i.e. self), nothing will happen.
For example, if you're scrolled halfway down a page and you click a hyperlink that refers to the current page, it will seem as though the link doesn't load, when in actual fact nothing needs to be loaded as the user is already on the right page.
The goal in this situation is to have the viewport moved to the top of the page, but I cannot get any event from ui-router for this event. I've tried $stateChangeStart and $stateChangeSuccess, but as no route change occurs, these do not fire.
My urls are of the form http://localhost:3000/projects/myproject and ui-router is configured as follows:
state('app.projects', {
url: '/projects/:projectname',
templateUrl: 'projects.html',
controller: 'ProjectsCtrl'
}).
Without adding extra logic in the controller (which would obfuscate the natural href="projects/myproject" format), what can be done to achieve this?
Without controller:
<a ui-sref="stateName({reload: true})" target="_blank">Link Text</a>
With controller:
$state.go($state.name, {}, {reload: true});
You can simply use # at the end of the link. href="projects/myproject#"

How to deal with templates of completely different areas (but same website) with AngularJS

I have a webapp with a main index.html that shows each page through an ng-view and a routeProvider.
Now I'm adding an entry page for users who are still not logged in. This page could also have his own ng-view to slide different sections for non logged users (welcome, what is, sign in, sign up ecc...) and his own head with css scripts ecc...
I'd rather that both the webapp index and the entry page index address to www.example.com (so nothing like www.example.com/welcome ).
I thought about a structure similar to this:
webapp/
main/
page1/
page2/
welcome/
section1/
section2/
index.html
welcome.js (angular module for the entry page)
.htaccess
index.html
webapp.js (angular module containing the routeProvider for the webapp)
Currently I have that .htaccess that rewrites all the fake queries to index.html so that everything is handled here.
So in particular:
1) How can I say to the routerProvider of webapp.js to go to /welcome/index.html when the user is not logged in, if I already use this condition for the webapp main page? (Should I use the run method? a brief example will be helpful)
.config(['$routeProvider', function($routeProvider){
$routeProvider
.when(...)
.when('/', {
templateUrl : 'main/webapp-main.html'
})
.when(...)
2) How do I prevent that everything in welcome/index.html will be loaded within the index.html ng-view? (maybe using ng-if to hide ng-view? or there is some way to control this behavour with the routerProvider?)
3) There is a better and simpler way to achieve all of this?
Thanks.
Update:
Ok I think there was an underlying problem in my question... I can't use a complete different page since everything is loaded in and switching to another page will cause the reload of the app loosing all the data.
So I suppose I should use the same main template for the entire website.
Then I add: there is a way in angularjs to load different style sheets dynamically?
this questions is old but i think is valid and can clarify someone a few thinks.
First of all you are suppose to use a single page for AngularJS apps, otherwise you will have to do something like a redirect link, and in your other-index.html load an entirely different Angular Application also loading every script needed in the first one.
1) Use ui-router is easy to work, and very robust, the only thing you need to have is a container for your ui-view then the ui-router will fill the container with the corresponding html
2) To prevent navigation you should do something like this:
angular.module('myApp', [])
.run(function($rootScope, mySessionService){
$rootScope.$on('$stateChangeStart',
function(event, next, nextParams, prev, prevParams) {
// The info of your currentUser could be obtain from a service
// or localStorage or cookies anyway you are already doing it
var authorized= checkAuthorization(next.authorazedRoles,
mySessionService.getCurrentRol());
if(!authorized) {
$rootScope.$state.go('defaultState');
// Or $rootScope.$emit('NOT_AUTHENTICATED');
// and some service will have to implement a listener for this emit
// $rootScope.$on('NOT_AUTHENTICATED', func..redirect to X State)
}
});
});

Updating URL in Angular JS without re-rendering view

I'm building a dashboard system in AngularJS and I'm running into an issue with setting the url via $location.path
In our dashboard, we have a bunch of widgets. Each shows a larger maximized view when you click on it. We are trying to setup deep linking to allow users to link to a dashboard with a widget maximized.
Currently, we have 2 routes that look like /dashboard/:dashboardId and /dashboard/:dashboardId/:maximizedWidgetId
When a user maximizes a widget, we update the url using $location.path, but this is causing the view to re-render. Since we have all of the data, we don't want to reload the whole view, we just want to update the URL. Is there a way to set the url without causing the view to re-render?
HTML5Mode is set to true.
In fact, a view will be rendered everytime you change a url. Thats how $routeProvider works in Angular but you can pass maximizeWidgetId as a querystring which does not re-render a view.
App.config(function($routeProvider) {
$routeProvider.when('/dashboard/:dashboardId', {reloadOnSearch: false});
});
When you click a widget to maximize:
Maximum This Widget
or
$location.search('maximizeWidgetId', 1);
The URL in addressbar would change to http://app.com/dashboard/1?maximizeWidgetId=1
You can even watch when search changes in the URL (from one widget to another)
$scope.$on('$routeUpdate', function(scope, next, current) {
// Minimize the current widget and maximize the new one
});
You can set the reloadOnSearch property of $routeProvider to false.
Possible duplicate question : Can you change a path without reloading the controller in AngularJS?
Regards
For those who need change full path() without controllers reload
Here is plugin: https://github.com/anglibs/angular-location-update
Usage:
$location.update_path('/notes/1');
I realize this is an old question, but since it took me a good day and a half to find the answer, so here goes.
You do not need to convert your path into query strings if you use angular-ui-router.
Currently, due to what may be considered as a bug, setting reloadOnSearch: false on a state will result in being able to change the route without reloading the view. The GitHub user lmessinger was even kind enough to provide a demo of it. You can find the link from his comment linked above.
Basically all you need to do is:
Use ui-router instead of ngRoute
In your states, declare the ones you wish with reloadOnSearch: false
In my app, I have an category listing view, from which you can get to another category using a state like this:
$stateProvider.state('articles.list', {
url: '{categorySlug}',
templateUrl: 'partials/article-list.html',
controller: 'ArticleListCtrl',
reloadOnSearch: false
});
That's it. Hope this helps!
We're using Angular UI Router instead of built-in routes for a similar scenario. It doesn't seem to re-instantiate the controller and re-render the entire view.
How I've implemented it:
(my solution mostly for cases when you need to change whole route, not sub-parts)
I have page with menu (menuPage) and data should not be cleaned on navigation (there is a lot of inputs on each page and user will be very very unhappy if data will disappear accidentally).
turn off $routeProvider
in mainPage controller add two divs with custom directive attribute - each directive contains only 'templateUrl' and 'scope: true'
<div ng-show="tab=='tab_name'" data-tab_name-page></div>
mainPage controller contains lines to simulate routing:
if (!$scope.tab && $location.path()) {
$scope.tab = $location.path().substr(1);
}
$scope.setTab = function(tab) {
$scope.tab = tab;
$location.path('/'+tab);
};
That's all. Little bit ugly to have separate directive for each page, but usage of dynamic templateUrl (as function) in directive provokes re-rendering of page (and loosing data of inputs).
If I understood your question right, you want to,
Maximize the widget when the user is on /dashboard/:dashboardId and he maximizes the widget.
You want the user to have the ability to come back to /dashboard/:dashboardId/:maximizedWidgetId and still see the widget maximized.
You can configure only the first route in the routerConfig and use RouteParams to identify if the maximized widget is passed in the params in the controller of this configured route and maximize the one passed as the param. If the user is maximizing it the first time, share the url to this maximized view with the maximizedWidgetId on the UI.
As long as you use $location(which is just a wrapper over native location object) to update the path it will refresh the view.
I have an idea to use
window.history.replaceState('Object', 'Title', '/new-url');
If you do this and a digest cycle happens it will completely mangle things up. However if you set it back to the correct url that angular expects it's ok. So in theory you could store the correct url that angular expects and reset it just before you know a digest fires.
I've not tested this though.
Below code will let you change url without redirection such as: http://localhost/#/691?foo?bar?blabla
for(var i=0;i<=1000;i++) $routeProvider.when('/'+i, {templateUrl: "tabPages/"+i+".html",reloadOnSearch: false});
But when you change to http://localhost/#/692, you will be redirected.

Resources