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"});
Related
I have an angular SPA with several modules, services, factories and controllers. I have written a helper service and put it in a common folder minifed js file that all my html pages reference. They contain common bits of data obtained by an AJAX call to a database. It has to run first because the rest of the app depends on values from this helper service. The issue is that the service returns out before the promise has been returned successful, so the helper service is always empty. I do not know what the best approach is to write a helper ajax call and have all files within an angular app reference values returned by it (so everything has to wait before the promise comes back and populates the helper service). I cannot put it in the scope at the top of the main controller, because factories and services cannot reference scope variables is that right? At least I dont understand how if so.
Have searched around and found lots of ways to reference a common service from multiple controllers, but little assistance on how to access that information if the data is a result of an ajax call.
Thanks in advance.
The issue is that the service returns out before the promise has been returned successful, so the helper service is always empty.
Try using resolve:
https://github.com/angular-ui/ui-router/wiki#resolve
https://docs.angularjs.org/api/ngRoute/provider/$routeProvider
Example syntax:
let routerConfig = ($stateProvider, $urlRouterProvider) => {
$urlRouterProvider.otherwise("/login");
$stateProvider
.state('login', {
url: "/login",
templateUrl: "templates/login.html",
controller: "LoginCtrl"
})
.state('home', {
url: "/home",
templateUrl: "templates/home.html",
controller: "HomeCtrl",
controllerAs: "home",
resolve: {
entries: function($rootScope, database) {
return database.getEntries($rootScope.user.uid);
}
}
})
}
There was no point displaying HomeCtrl so I ensured entries from database get resolved before loading... I think you can use similar technique in your code.
If you're using a central service that other pieces of the application depend on, you can use two approaches.
Approach one would be to give the top level controller access to the data and then pass it down to all other components.
The other approach would be giving each individual component/controller direct access to the data.
Either way the code would be kind of similar. There's plenty of ways to do it but the simplest solution I use is just taking advantage of object reference:
Factory:
//you can use factory or service doesn't matter.
.factory('dataFactory', function(){
var store = {
data: null
};
//Return the entire store object
function subscribe() {
return store;
};
function fetchData() {
$http.get('someUrl.com')
.then(function(res) {
//Set data to a property on the store.
store.data = res.data;
});
}
return {
subscribe: subscribe,
fetchData: fetchData
};
}
Controller:
.controller('someController', function(dataFactory) {
//Essentially copying over the store object in the factory by reference
this.store = dataFactory.subscribe();
//call the ajax
dataFactory.fetchData();
}
Template:
<div ng-controller="someController as ctrl">
{{ctrl.store.data}}
</div>
Pros
Any controller in the application can get access to the store in the factory
Since they are referencing the same object, you don't need to do any crazy event emitters or anything to notify all the controllers if the data gets updated in the factory.
You are also caching the data in the factory. If any controllers get destroyed and re-created they can just subscribe again. The data doesn't disappear.
Cons
It's bound by object reference, so any changes made to the store object anywhere in the application will change the object everywhere. This can be good or bad depending on what you want to happen in your application.
If you are working on a large application this can get messy, especially if you're not the only one working on it. However if this is what your application requires and you need a more robust option, i suggest checking out state management tools such as redux.
Checkout this codepen I made which implements a very simple version of redux.
I'm a newbie in AngularJS, and I was using ui.router.
What I am trying to do is load html from different portals, like:
/s3/home
/goo/home
/gle/home
All prefix like s3, goo, gle are from backend, I have to get it first then load my pages, any idea for this, any way to put a variable in relative path, like
/{{portal}}/home
Mockup for expression:
angular.module('app')
.config(function ($stateProvider) {
$stateProvider
.state('{{portal}}.home', { //portal from backend
url: '/',
views: {
'content#': {
templateUrl: 'scripts/app/{{portal}}/home.html', //portal from backend
controller: 'MainController'
}
}
});
})
Find a way to do it, dynamic templateURL will do the same thing
http://fredparke.com/blog/angularjs-directive-dynamic-template
I want to use it in Javascript, is it possible
No i'm afraid not. Use Curly braces to bind expressions to elements in your html. I think you need to rethink more fundamentally your application and why you want to have "variable" template urls in such a way. Try and read up on REST as that's probably what you want to have for your backend. The frontend can then parameterise requests via url/query parameters
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.
I'm trying to get my view template updated every 10 minutes. Using this setup in the state config doesn't work:
.state('home', {
url: '/',
controller: 'landing',
templateProvider: function($templateFactory, $interval) {
var templateId = 0;
return $interval(function(){
var template = templateId % 2 == 0 ?
'landing-primary.html':'landing-secondary.html';
templateId++;
return $templateFactory.fromUrl('views/templates/' + template);
}, 600000);
}
})
What's the best way to achieve such work?
The templateProvider option should be a function that returns an html string or a promise that resolves with an html string. It's mainly present so that you can generate html that somehow makes use of $stateParams.
What you're trying to do wouldn't normally be done through route/state definitions; what you've described is logic that should be in a directive or controller. While it's hard to say for sure without more information about exactly what you're trying to achieve, it sounds like what you really need is a single "landing" page with the content of both templates divided by an ng-switch directive that gets bound to a model property. Then in your controller you would set an $interval to change that model property every 10 minutes.
Alternatively, maybe what you want is two states, in which case the pair of states would each have in their corresponding controllers a $timeout that toggles to the other state.
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'});