Populate Scope Values from URL on Initial Load - angularjs

I am new to Angular so bear with me.
I have a controller that handles the search functionality within a page.
As a user changes the search the url changes to reflect the user interaction. Then there are $http.post calls to an API to retrieve those values within the URL. A repeater in a separate controller is updated appropriately.
This works great and the scope changes correctly.
But how do I handle initial load?
If a user clicks a saved search.
Example:
http://blah/blah/blah/Search/Status-1%7CBeds-3
I would want the search fields and the scope to be set appropriately but then the same functionality should continue.
What is the best way of doing this?
If code is needed then ask, but this is more of a which direction to go question then a fix my code question.

You probably want AngularJS routing and the $routeParams object.
If that is not adequate, you can use the $location service to extract information from the URL and write it to the $scope in your controller constructor function.

If you use ui-router you can define the search string as a parameter that can be used when deep linking
app.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('home', {
url:'/home',
templateUrl: 'templates/home.html',
controller: 'HomeController'
})
.state('search', {
url: '/search/:searchtoken',
templateUrl: 'templates/search.html',
controller: 'SearchController'
});
http://www.funnyant.com/angularjs-ui-router/

One solution is to populate the search variable with the url params. Something like:
if params
$scope.searchInputVal = params
$scope.doPostRequest()
(sorry for the coffee script syntax)
and just ensure whatever function you have to update these search parameters is firing onChange() or onClick() whichever you're using to fire the post request to begin with.

Related

Capturing the route change in AngularJS when no route matches

In AngularJS, is there a way to intercept a route change that is not defined in the routeProvider so the route can be looked up in the database and, if a valid match in the database, the new route can be added to the routeProvider?
I've read it is possible to add, dynamically, a route, but I need to do it when the current route has no match.
I would have used the otherwise method of $routeProvider to load a predefined page (controller) to handle undefined routes.
otherwise({
templateUrl: 'addRoute.html',
});
And then, into this controller, get the current route requested using $location ($location.url()).
Add this route dynamically if needed :
$route.routes['/new'] = {templateUrl: 'new.html'};
Finally, redirect to this route using :
$location.path('/new');
Obviously, for this to work you will need to inject $route and $location as dependency to your controller.
Assuming you can do it in controller, you can capture this event as following:
$rootScope.$on("$routeChangeSuccess", function (event, next, current) {
if(!angular.isDefined($route.current.$$route))
addDynamicRoute('using techniques mentioned above');
else
handleOtherStuff();
});

Accommodating multiple states through $stateprovider in one $resource in angularjs?

I have a requirement where the angularjs states for one particular page would be different. Say, /items/create and /items/list -- those 2 are my urls for 2 different states. Now, how do I accommodate them in one $resource? Is it possible? Or do I have to create 2 $resource or 2 factories?
<angular module>.config(['$stateProvider', function($stateProvider){
$stateProvider
.state('items', {
url: '/items/create',
templateUrl: '<view>'
})
.state('items.List', {
url: '/items/list',
templateUrl: '<view>'
});
}]);
<angular module>.factory('Items', ['$resource', function($resource){
return $resource('/items');
}]);
Now this will not work, as the state urls are different. If i make the resource with /items/create, the first url will be executed and if make the resource with /items/list the second will be executed.
I need to make a resource which will refer to both of the states provided in the state provider. Is it possible?
Please note, I want to have them called at the page load itself before making any manual state transfer.
It's ugly but you could make the resource url /items/:state and then pass in a state property when you call Items.query/get/post
Items.post({state:"create"});
Items.get({state:"list"});

Duplicate controller when using angularjs

I'm usnig AngularJs 1.2.25. I have a route config:
$routeProvider.when(
'/config-root',
{
templateUrl: configRootTemplate,
controller: "ClientConfig",
}
).when(
'/config-action/:action/:_id',
{
templateUrl: configActionTemplate,
controller: "ClientConfigAction",
}
).otherwise({redirectTo: '/'});
In the ClientCOnfig controller, I have a $scope.listConfig variable binding with template for creating, updating list of config.
Everything ok when the first time I visit "config-root" route, I can generate, update... the list.
But when the second time or so far, $scope.listConfig change properly when generate list, update... but the template does not change.
I think when I visit that route again, a new instance of $scope created and does not binding with the template.
How can I fix it?
You can use rootScope to preserve the value for the next time.
change that $scope to $rootScope and access that when ever its required.
If you don't want to pollute the $rootScope you can just store the values in a localStorage as a string and fetch it when ever its required.
// To store the value
localStorage['config'] = JSON.stringify(someObj)
// To fetch the value
var myConfigObj = JSON.parse(localStorage['config'])

How to Pass Variables When Using $routeProvider

I'm using $routeProvider to create a one page app where users press continue to go to the next step. It is important to pass variables to the next page whenever a user clicks continue so I followed some advice and created my own service which has persistent variables. This all works great except that I can only get variables from the service, I don't know how to update the variables. Here is my code:
myApp.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/pick_categories', {
templateUrl: '/pick_categories.html',
controller: 'MeetupDataCtrl'
}).
when('/pick_times', {
templateUrl: '/pick_times.html',
controller: 'MeetupDataCtrl'
}).
when('/events', {
templateUrl: '/events.html',
controller: 'MeetupDataCtrl'
}).
otherwise({
redirectTo: '/pick_categories'
});
}]);
myApp.service("meetupService", function(){
this.checked_categories = [];
});
myApp.controller('MeetupDataCtrl', ['$scope', '$http', '$location', '$resource', 'meetupService', function MeetupDataCtrl($scope, $http, $location, $resource, meetupService) {
$scope.checked_categories = meetupService.checked_categories;
}]);
Then in the view I have checked_categories bound to an input field.
I know the problem is that I'm getting the service's variables on init, but I'm not updating the service's variables from the scope after I change routes. Any ideas on how I could do this? (or if there are other best practices)
You could in fact change the service properties directly ... :
meetupService.checked_categories.push({ something: 'something'});
... but it's better to encapsulate the state properties of a service so you can do something like the following from your controller:
meetupService.addCategory('theCheckedCategory');
Do mind that services are singletons in Angular; there will be only one meetupService in your Angular application. This means that once the user has modified the checked_categories array somehow they will have that some array until they refresh/reload your website.
Also note that passing state information via url arguments is in most cases not necessary when building a single page app (which Angular is).
It sounds like your trying to build a wizard and if I'm guessing right you don't need anything of the above. Wizards are actually quite easy to make in Angular because all the state information is kept, ... well as long as you want it to.
See this plunker for a simple wizard example.
Edit:
Oh, and if you really need to pass arguments to the route, you can do that with the builtin $location service.
// change the path
$location.path('/newValue')
// change the query string / url arguments
$location.search({myArg: 'value', myOtherArg: 'anotherValue'});

Otherwise on StateProvider

Using angular-ui-router, How can I use the otherwise method on $stateProvider or how can I use it at all ?
You can't use only $stateProvider.
You need to inject $urlRouterProvider and create a code similar to:
$urlRouterProvider.otherwise('/otherwise');
The /otherwise url must be defined on a state as usual:
$stateProvider
.state("otherwise", { url : '/otherwise'...})
See this link where ksperling explains
You can with $stateProvider using the catch all syntax ("*path"). You just need to add a state config at the bottom of your list like the following one:
$stateProvider.state("otherwise", {
url: "*path",
templateUrl: "views/error-not-found.html"
});
All the options are explained in https://github.com/angular-ui/ui-router/wiki/URL-Routing#regex-parameters.
The nice thing of this option, as opposed to $urlRouterProvider.otherwise(...), is that you 're not forced to a location change.
You can also manually inject $state into the otherwise function, which you can then navigate to a non-url state. This has the benefit of the browser not changing the addressbar, which is helpful for handling going back to a previous page.
$urlRouterProvider.otherwise(function ($injector, $location) {
var $state = $injector.get('$state');
$state.go('defaultLayout.error', {
title: "Page not found",
message: 'Could not find a state associated with url "'+$location.$$url+'"'
});
});
I just want to chime in on the great answers that are already provided. The latest version of #uirouter/angularjs marked the class UrlRouterProvider as deprecated. They now recommend using UrlService instead. You can achieve the same result with the following modification:
$urlService.rules.otherwise('/defaultState');
Additional methods: https://ui-router.github.io/ng1/docs/1.0.16/interfaces/url.urlrulesapi.html
Ok, the silly moment when you realize that the question you asked is already answered in the first lines of the sample code! Just take a look at the sample code.
angular.module('sample', ['ui.compat'])
.config(
[ '$stateProvider', '$routeProvider', '$urlRouterProvider',
function ($stateProvider, $routeProvider, $urlRouterProvider) {
$urlRouterProvider
.when('/c?id', '/contacts/:id')
.otherwise('/'); // <-- This is what I was looking for !
....
Take a look here.
The accepted answer references angular-route asks about ui-router. The accepted answer uses the "monolithic" $routeProvider, which requires the ngRoute module (whereas ui-router needs the ui.router module)
The highest-rated answer uses $stateProvider instead, and says something like .state("otherwise", { url : '/otherwise'... }),
but I can't find any mention of "otherwise" in the documentation it links. However, I see that $stateProvider is mentioned in this answer where it says:
You can't use only $stateProvider. You need to inject $urlRouterProvider
That's where my answer might help you. For me, it was sufficient to use $urlRouterProvider just like this:
my_module
.config([
, '$urlRouterProvider'
, function(
, $urlRouterProvider){
//When the url is empty; i.e. what I consider to be "the default"
//Then send the user to whatever state is served at the URL '/starting'
//(It could say '/default' or any other path you want)
$urlRouterProvider
.when('', '/starting');
//...
}]);
My suggestion is consistent with the ui-router documentation, (this specific revision), where it includes a similar use of the .when(...) method (the first call to the function):
app.config(function($urlRouterProvider){
// when there is an empty route, redirect to /index
$urlRouterProvider.when('', '/index');
// You can also use regex for the match parameter
$urlRouterProvider.when(/aspx/i, '/index');
})

Resources