How can I get the previous url using $ionicHistory.viewhistory? - angularjs

I want to track the page where the user was previously than the current one.
I was trying to use $ionicHistory.viewHistory() but I can manage to get it. I'm new to angularjs and $ionic so I guess this is a newbie question.
This whole thing is with the purpose of doing a funnel analysis for a single page web app using Piwik but since it doesn't have a proper funnel plugin (thanks Piwik) I'll have to implement it myself. So if you have any advice on the topic it would be great to hear from you.

So what you are looking for is $ionicHistory.backView() or $ionicHistory.backTitle(). If you are using angular states and routing and views.
So in a controller you would call:
$scope.lastView = $ionicHistory.backView()
This gives the the last view you were in. So if you go from A to B it will give you A.
If you want the title of the last view call this in a controller:
$scope.lastViewTitle = $ionicHistory.backTitle()
This gives you a string, which is whatever title you gave the previous view. This would return "My Page" if you called backTitle() after you just left this view.
<ion-view view-title="My Page">
<ion-content>
Hello!
</ion-content>
</ion-view>
You can read more here:
http://ionicframework.com/docs/api/service/$ionicHistory/
If you dont want views but states, you should be able to grab the previous state on $stateChangeSuccess that is broadcast.
$rootScope.$on('$stateChangeSuccess', function (ev, to, toParams, from, fromParams) {
//assign the "from" parameter to something
});

var history = $ionicHistory.backView();//returns an object with data about the previous screen. console.log(history) to see the entire data.
var previous_statename = history.stateName;//compare this
var previous_url = history.url;
var previous_title = history.title;

Use:
$ionicHistory.backView().stateName
which will have this value:
app.tab.contacts

Related

What is a good practice for redirecting in an angular SPA

I am building an angular app and have encountered several instances where I would like to redirect the user to a certain page. But that information about whether a user should be redirected or not is typically received after a server side request.
In the time it takes to do a server request, the original page starts rendering and hence creates a bad UX.
A case in point would be redirecting to login page when user is unauthorized.
Question 1 I know how to handle these cases individually. But was wondering if there is some standard pattern I can follow to solve this issue.
Question 2 Is there a standard pattern to control when to start rendering the page when information is being fetched from server. for instance
my view has
{{user.name}}
and controller has following code:
userService.load_user().then(function(user) {
$scope.user = user;
});
I don't want anything displayed till user is loaded, maybe just a loading sign. Currently i can do it as such:
//controller
userService.load_user().then(function(user) {
$scope.user = user;
$scope.loaded = true;
});
and
<!-- view -->
<div ng-show="!loaded">
<img src="loading.gif"/>
</div>
<div ng-show="loaded">
real code here.
</div>
This gets complicated when I want to wait on more than one requests.
Use the resolve property of the routes. Am assuming you're using ngRoutes or ui-router. Both include the resolve property on their routes.
To add a spinner or something similar while you wait for them to resolve, listen for the view change events within the shell view controller (assuming you have one) and add/remove the spinner accordingly.
By shell controller I just mean the highest level view within which the others are nested. It may or may not have a controller, but usually does. You might have a showSpinner property on that scope:
myApp.controller('mainCtrl', function($scope){
$scope.showSpinner = false;
$scope.$on('$stateChangeStart', function(){
$scope.showSpinner = true;
});
$scope.$on('$stateChangeSuccess', function(){
$scope.showSpinner = false;
});
});
Then you could just use ng-show='showSpinner' or ng-show='!showSpinner' on the spinner html element and the view element respectively.
This is the basic idea. You will probably end up with something more elaborate.
Here is a Plunker. There is a little more going on there (abstract state etc) than you requested, but you will quickly see how the resolve property is used and how the state is diverted.

How to implement routing based on the $rootScope variable value

I have a requirement to implement a data collection "wizard" app, using AngularJS.
As the user progresses onto the next wizard page, I'm faced with a choice: a) to have each page partial have its own "Next" button, with hg-click explicitly calling the pre-defined next partial page or b) to have just one pair of "Next/Previous" buttons and implement navigation in a more dynamic way, by storing the curtest wizard step in a $rootScope.
My question: If I chose option "b", how what would be the way to implement dynamic routing based on the $rootScope.currentWizardStep value?
Or, maybe, there is a better way to do all this. If You know of such as way, please share :)
You're looking to implement $routParams.
This allows you to name segments of a URL, which then turn into a key/value pair.
from the docs:
// Given:
// URL: http://server.com/index.html#/Chapter/1/Section/2?search=moby
// Route: /Chapter/:chapterId/Section/:sectionId
//
// Then
$routeParams ==> {chapterId:1, sectionId:2, search:'moby'}
Then within your controller, you just have to check the URL to determine which page they are on. Using the example given from the docs, if you wanted to identify which chapter they are on, you would do:
var chapter = $routeParams.chapterId;
This would still allow you to keep just one set of 'next/previous' buttons. I don't know how you're incrementing pages (different names, page numbers, etc). But it should be fairly minor to keep track of what pages are next/previous. Especially if you had a master array of all the pages & the order that you expect them to be in.
var wizardPages = {
one: {previous: 'start.html', current: 'one.html', next: 'two.html'},
two: {previous: 'one.html', current: 'two.html', next: 'three.html'},
three: {previous: 'two.html', current: 'three.html', next: 'end.html'}
};
$scope.next = function(){
var current = $routeParams.page;
$scope.template = wizardPages[current].next;
};
$scope.previous = function(){
var current = $routeParams.page;
$scope.template = wizardPages[current].previous;
};
And then your HTML
<div class="" ng-include="template"></div>
And wherever you configure your routes:
$routeProvider
.when('/wizard', {templateURL: 'view/wizard.html'})
.when('/wizard/:page', {templateURL: 'view/wizard.html'});
Your URL would look something like: www.example.com/wizard/one
This would allow you to continue using partials (which would be loaded into your ng-includes)
Populating the $rootScope with statefull data is always a bad idea. Depending on how big your page will be (or to be more precisely: how many subpages you will have) I would even recommend to not use routing at all, but work with the ng-show-Directive and a single Controller, incrementing a value representing the current subpage.
Something like this:
<div ng-show="pageNum == 1">
<h1>First Page</h1>
</div>
<div ng-show="pageNum == 2">
<h1> Second Page</h1>
</div>
<input type="button" ng-click=pageNum++" value="Next Page"/>
Of course this is only possible if you dont need render the Subpages serverside.

How to append url to the end of a button link in angularjs?

Assuming I am currently on the page:
www.mysite.com/root/#/?page=orderpage
On the page, I have a link:
Click Here for Mobile
I want to make it such that when the user clicks on the "Click Here For Mobile" link, I can take the user to:
www.mysite.com/root/mobile/#/?page=orderpage
Notice that the URL is similar to what it was before (preserving whatever parameters were there), except there is a "mobile" in between the root and the #.
How do I make it such that the "Click Here For Mobile" link will have the redirect to the appropriate URL as described above?
Is it good practice to do this? Examples appreciated.
As Ajay said, client-side routing will not be possible in this case.
So what you're left with is either doing (like Ajay said):
<a target="_self" href="/root/mobile/#/?page=orderpage">
Or, you could define a function (in a service, in the specified controller, or someplace else where you have access to it) that takes a string and changes the $window.location.href (this will result in a page reload).
Something like this:
app.controller("SomeCtrl", function ($scope, $location, $window) {
$scope.changeUrl = function (url) {
var newUrl = $location.$$absUrl.replace("/#/", url);
$window.location.href = newUrl;
};
});
And then in your html you would use:
Go mobile
Without Javascript enabled (which I'm assuming you're not gonna be supporting with an Angular app) this would not take you anywhere. In that case, Ajay's solution is definately the prefered one.
The benefit of turning it into a function is that all you have to pass is what you're changing before the "/#/".
Good luck :)

AngularJs $location.path with full url

I want to route the user to an url if he clicks ok in a modal. In my controller i receive urls like
var newUrl = http://localhost:3000/#/dashboard
var newUrl = http://localhost:3000/#/users
as variable.
If i then use
$location.path(newUrl);
it does not work. I also tried
$location.url(newUrl);
but my URL gets encoded like this.
http://localhost:3000/#/#%2Fdashboard
Is there a way to get only the path of the url?
Edit
this code is part of a service. A user make some inputs in a form and clicks on another link for example in the menu. Then a popup appears where he is asked to skip his form changes. If he clicks yes i get the requested url. This is from my development environment on the server of course it will be another url. So i can not just use
$location.path("/users")
for example
I ran into this same problem when having Angular preventDefault $locationChangeStart events, force a save, and only redirect upon success. I define the following function in the body of the controller:
var baseLen = $location.absUrl().length - $location.url().length;
function getPath(fullUrl) {
return fullUrl.substring(baseLen);
}
It doesn't seem like a clean solution, but as a work around, it does the job. A RegEx might work better for you, if you don't know that your URLs are pointing to the same site.
You can use $location.absUrl().
See the official documentation: enter link description here
This method is getter only.
Return full url representation with all segments encoded according to rules specified in RFC 3986.
May I offer a different solution:
$scope.$on('$locationChangeStart', function(e) {
if (meetsTheRequirementsToLeave()) {
return;
}
var newPath = $location.path();
e.preventDefault();
checkIfUserWantsToLeave().then(function() {
$location.path(newPath);
});
});
Within this event $location.path() returns the new path.

Backbone.js change url without reloading the page

I have a site that has a user page. On that page, there are several links that let you explore the user's profile. I'd like to make it so that, when one of those links is clicked on, the url changes, but the top third of the page containing the user's banner doesn't reload.
I'm using Backbone.js
I have a feeling that I'm in one of those situation where I have such a poor understanding of the problem I'm dealing with that I'm asking the wrong question, so please let me know if that appears to be the case
My mistake was assuming that there was a special, built-in way of doing this in backbone. There isn't.
Simply running the following line of code
window.history.pushState('object or string', 'Title', '/new-url');
will cause your browser's URL to change without reloading the page. You can open up the javascript console in your browser right now and try it with this page. This article explains how it works in more detail (as noted in this SO post).
Now I've just bound the following event to the document object (I'm running a single page site):
bindEvents: () ->
$(document).on('click', 'a', #pushstateClick)
pushstateClick: (e) ->
href = e.target.href || $(e.target).parents('a')[0].href
if MyApp.isOutsideLink(href) == false
if e.metaKey
#don't do anything if the user is holding down ctrl or cmd;
#let the link open up in a new tab
else
e.preventDefault()
window.history.pushState('', '', href);
Backbone.history.checkUrl()
See this post for more info.
Note that you CAN pass the option pushstate: true to your call to Backbone.history.start(), but this merely makes it so that navigating directly to a certain page (e.g. example.com/exampleuser/followers) will trigger a backbone route rather than simply leading to nowhere.
Routers are your friend in this situation. Basically, create a router that has several different routes. Your routes will call different views. These views will just affect the portions of the page that you define. I'm not sure if this video will help, but it may give you some idea of how routers interact with the page: http://www.youtube.com/watch?v=T4iPnh-qago
Here's a rudimentary example:
myapp.Router = Backbone.Router.extend({
routes: {
'link1': 'dosomething1',
'link2': 'dosomething2',
'link3': 'dosomething3'
},
dosomething1: function() {
new myapp.MyView();
},
dosomething2: function() {
new myapp.MyView2();
},
dosomething3: function() {
new myapp.MyView3();
}
});
Then your url will look like this: www.mydomain.com/#link1.
Also, because <a href=''></a> tags will automatically call a page refresh, make sure you are calling .preventDefault(); on them if you don't want the page to refresh.

Resources