I am using a $stateprovider as follows from angular-ui-router in my angular application:
.state('order', {
url: "/order/:id",
templateUrl: "/myapp/order"
})
In the above scenario, we are passing an id to the controller and we can call it as ui-sref="order({id: 1234})".
But now i want to make a direct call to the backend by not using a controller and pass the above as follows:
.state('order', {
url: "/order",
templateUrl: "/myapp/order/:id"
})
But obviously my syntax is wrong here.
How do i achieve this scenario?
I created working example. It is adjsuting thiw Q & A:
Trying to Dynamically set a templateUrl in controller based on constant
Let's have templates template-A.html and template-B.html in our example.
The state def with templateProvider would look like this
$stateProvider
.state('order', {
url: '/order/:id',
templateProvider: function($http, $templateCache, $stateParams) {
var id = $stateParams.id || 'A';
var templateName = 'template-' + id + '.html';
var tpl = $templateCache.get(templateName);
if (tpl) {
return tpl;
}
return $http
.get(templateName)
.then(function(response) {
tpl = response.data
$templateCache.put(templateName, tpl);
return tpl;
});
},
controller: function($state) {}
});
And now we can call it like this
<a href="#/order/A">
<a href="#/order/B">
Check it here
And what's more, with latest version of angularjs we can even make it super simple:
$templateRequest
Updated plunker
.state('order', {
url: '/order/:id',
templateProvider: function($templateRequest, $stateParams) {
var id = $stateParams.id || 'A';
var templateName = 'template-' + id + '.html';
return $templateRequest(templateName);
},
controller: function($state) {}
});
Related
app.js:
$stateProvider.state('datasource', {
url: '/datasource',
templateUrl: 'views/datasource.html',
controller: 'datasourceController'
});
$stateProvider.state('datasourceList', {
url: '/datasource/:datasourceId',
templateUrl: 'views/datasource.list.html',
controller: 'datasourceController'
});
Then, I've a function activated onClick defined in (datasourceController)
$scope.submitSelected = function() {
if (angular.isDefined($scope.selectedSource)) {
$scope.datasource = dataSourcesService.find($scope.selectedSource.id);
$state.go('datasourceList', {datasourceId : datasource});
}
}
As I said, in my datasource.html view have an element click that triggers submitSelected() function
I can retrieve data successfully from my service based on ID when call it in function.
Problem is, i cant access the results (scope) of it in the view datasource.list.html after changing the state.
Add 'param' in state config
$stateProvider.state('datasource', {
url: '/datasource',
templateUrl: 'views/datasource.html',
controller: 'datasourceController'
});
$stateProvider.state('datasourceList', {
url: '/datasource/:datasourceId',
templateUrl: 'views/datasource.list.html',
params: ['index', 'anotherKey'],
controller: 'datasourceController'
});
And get values using $stateParams in another controller
app.controller('datasourceController', function($scope, $stateParams) {
var index = $stateParams.index;
var anotherKey = $stateParams.anotherKey;
});
i am just learning basics of angular and today it started to change my app using a factory to get data and implementing route provider ! So far everything works fine! But when I try to add data on another view and head back to my list view scope is reloaded again from factory and no added data shows up.
My approach won't work because each time change my view I will call my controller which reloads data from factory! What can I do to make my Add template will work and changes data everywhere else too.
Maybe somebody can give me a tip how to cope with this problem ?
script.js
var app = angular.module('printTrips', ['ngRoute']);
app.factory('tripFactory', function($http) {
return{
getTrips : function() {
return $http({
url: 'trips.json',
method: 'GET'
})
}
}
});
app.controller('TripController', function($scope, $filter, tripFactory) {
$scope.trips = [];
tripFactory.getTrips().success(function(data){
$scope.trips=data;
var orderBy = $filter('orderBy');
$scope.order = function(predicate, reverse) {
$scope.trips = orderBy($scope.trips, predicate, reverse)};
$scope.addTrip = function(){
$scope.trips.push({'Startdate':$scope.newdate, DAYS: [{"DATE":$scope.newdate,"IATA":$scope.newiata,"DUTY":$scope.newduty}]})
$scope.order('Startdate',false)
$scope.newdate = ''
$scope.newiata = ''
$scope.newduty = ''
}
$scope.deleteTrip = function(index){
$scope.trips.splice(index, 1);
}
});
});
view.js
app.config(function ($routeProvider){
$routeProvider
.when('/',
{
controller: 'TripController',
templateUrl: 'view1.html'
})
.when('/view1',
{
controller: 'TripController',
templateUrl: 'view1.html'
})
.when('/view2',
{
controller: 'TripController',
templateUrl: 'view2.html'
})
.when('/addtrip',
{
controller: 'TripController',
templateUrl: 'add_trip.html'
})
.otherwise({ redirectTo: 'View1.html'});
});
Here is my plunker
Thanks for your help
You should use Service instead of Factory.
Services are loaded each time they are called. Factory are just loaded once.
app.service('tripFactory', function($http) {
return{
getTrips : function() {
return $http({
url: 'trips.json',
method: 'GET'
})
}
}
});
I am confused. For a long time now I have been using stateParams as a means of find out the stateParams inside a templateUrl.
Now I tried to do the same in a resolve and it does not work. In fact nothing happens when I use stateParams.
However by chance I found that I can use $stateParams in the resolve and it works.
Can someone tell me what is the difference and why do I need to use stateParams in the templateUrl and $stateParams in the resolve?
var auth = {
name: 'auth',
url: '/Auth/:content',
templateUrl: function (stateParams) {
var page = 'app/auth/partials/' + stateParams.content + '.html';
return page;
},
controller: function ($scope, authService) {
$scope.aus = authService;
},
resolve:
{
init: function ($stateParams) {
var x = 99;
return true;
}
}
};
I've created working example here, showing that $statePrams are accessible in the resolve
// States
$stateProvider
.state('auth', {
url: "/auth/:content",
templateUrl: 'tpl.html',
controller: 'AuthCtrl',
resolve : {
init : ['$stateParams' , function($stateParams){
return { resolved: true, content: $stateParams.content };
}]
}
})
Controller
.controller('AuthCtrl', ['$scope', 'init', function ($scope, init) {
$scope.init = init;
}])
and this could be the calls
auth/8
auth/xyz
Check it here
So I am having trouble with stateParams - I have done this before and have never had an issue but I can't seem to pass anything to the state when I call go.
If you look at the demographics section you can see that I am returning a function for the template URL and it works just fine when I hard code the GUID however my personId variable is always undefined. I am trying to figure out what I have done to cause this however I can't for the life of me.
memberApp.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
$stateProvider.state('quickScreen', {
url: "#/Components/QuickScreen",
templateUrl: "/Components/QuickScreen/index.html",
controller: "quickScreenController",
});
$stateProvider.state('quickScreen.detail', {
url: '#/quickScreen/:step',
templateUrl: function ($stateParams) {
console.log($stateParams.step);
return "/Components/QuickScreen/" + $stateParams.step + "/" + $stateParams.step + ".html";
}
});
$stateProvider.state('demographics', {
views: {
"memberDemographics": {
templateUrl: function ($stateParams) {
console.log("PersonId: " + $stateParams.personId);
//return '/Demographics/Index/' + $stateParams.personId;
return '/Demographics/Index/' + 'f75fb494-xxxx-xxxx-xxxx-a17b01336ca5';
},
controller: 'demographicsSearchController'
}
},
});
});
memberApp.controller('memberAppController', function ($scope, $state, $stateParams) {
console.log("About to load to demographics");
$state.go('demographics', { personId: 'f75fb494-fe7a-4564-be93-a17b01336ca5' });
});
You can try with this ,We can take Particular Id from stateParams and assign to some variable you can use that variable or u can user direactly
( $state.go('demographics', { personId: $stateParams.personId });).
memberApp.controller('memberAppController','$stateParams','$scope','$scope',
function ($scope,$state, $stateParams)
{
console.log("About to load to demographics");
var Id = $stateParams.personId;
$state.go('demographics', { personId: Id });
});
Is it possible to load a controller, it's js file, and a template dynamically based on a route group? Psuedo code which doesn't work:
$routeProvider.when('/:plugin', function(plugin) {
templateUrl: 'plugins/' + plugin + '/index.html',
controller: plugin + 'Ctrl',
resolve: { /* Load the JS file, from 'plugins/' + plugin + '/controller.js' */ }
});
I've seen a lot of questions like this one but none that loads the js file/controller based on a route group.
I managed to solve it inspired by #calebboyd, http://ify.io/lazy-loading-in-angularjs/ and http://weblogs.asp.net/dwahlin/archive/2013/05/22/dynamically-loading-controllers-and-views-with-angularjs-and-requirejs.aspx
Using http://dustindiaz.com/scriptjs
app.js
app.config(function($controllerProvider, $compileProvider, $filterProvider, $provide) {
app.register = {
controller: $controllerProvider.register,
directive: $compileProvider.directive,
filter: $filterProvider.register,
factory: $provide.factory,
service: $provide.service
};
});
Then i register the "load controller by group" route.
$routeProvider.when('/:plugin', {
templateUrl: function(rd) {
return 'plugin/' + rd.plugin + '/index.html';
},
resolve: {
load: function($q, $route, $rootScope) {
var deferred = $q.defer();
var dependencies = [
'plugin/' + $route.current.params.plugin + '/controller.js'
];
$script(dependencies, function () {
$rootScope.$apply(function() {
deferred.resolve();
});
});
return deferred.promise;
}
}
});
controller.js
app.register.controller('MyPluginCtrl', function ($scope) {
...
});
index.html
<div ng-controller="MyPluginCtrl">
...
</div>
You can use RequireJS to do this. Something like:
$routeProvider.when('/:plugin',{
templateUrl: 'plugins/' + plugin + '/index.html',
controller: plugin + 'Ctrl',
resolve: {myCtrl: function($q){
var deferred = $q.defer();
require('myCtrlFile',function(){
deferred.resolve();
});
return deferred.promise;
}}
});
You will also need to register the controller dynamically. By exposing your providers in the app config.
app.config(function($controllerProvider,$compileProvider,$filterProvider,$provide){
app.register =
{
controller: $controllerProvider.register,
directive: $compileProvider.directive,
filter: $filterProvider.register,
factory: $provide.factory,
service: $provide.service
};
});
You controller file might then look like:
define(['app'],function(app){
app.register.controller('myCtrl',MyCtrlFunction);
});
This is just the general idea. I use a similar implementation to the one described here
I also use ui-router. I'm not certain if behavior is the same with ngRoute.
Here is some solution you can do for this code
$routeProvider.when('/:plugin', function(plugin) {
templateUrl: 'plugins/' + plugin + '/index.html',
controller: fun,
loadFrom:"assets/controller/myJsController"// this is our custom parameter we are passing to controller to identify the remote controller file.
});
We will create a parent function for all controller and will call all controller within this function as per defined in route configuration (in loadFrom key of route configuration).
function fun($scope, $http, $location, $timeout, $route) {
$timeout(function () {
var path = $route.current.loadForm;
$http.get("${pageContext.servletContext.contextPath}/resource/controller/" + path + ".js")
.then(function (rsp) {
eval(rsp.data);
});
});
};
in assets/controller/myJsController.js file the code will be as
(function($scope){
//the whole code for controller will be here.
$scope.message="working."
})($scope)
Only thing you have to remember that in parent function you have to use all dependencies.
Simplest way with active this with less amount of code
require.js config file.
require.config({
urlArgs: 'v=1.0',
baseUrl: '/'
});
app.config(['$controllerProvider', '$compileProvider', '$filterProvider', '$provide','$routeProvider',function($controllerProvider, $compileProvider, $filterProvider, $provide,$routeProvider) {
app.register = {
controller: $controllerProvider.register,
directive: $compileProvider.directive,
filter: $filterProvider.register,
factory: $provide.factory,
service: $provide.service
};
// Resolver to load controller, service, directive
var resolveController = function(dependencies) {
return {
load: ['$q', '$rootScope', function ($q, $rootScope) {
var defer = $q.defer();
require(dependencies, function () {
defer.resolve();
$rootScope.$apply();
});
return defer.promise;
}]
}
};
$routeProvider
.when("/home", {
templateUrl : "templates/home.html",
controller: 'HomeCtrl',
resolve: resolveController(['controller/HomeCtrl'])
})
.when("/ContactUs", {
templateUrl : "templates/ContactUs.html",
controller: 'ContactUsCtrl',
resolve: resolveController(['controller/ContactUsCtrl'])
})
.when("/About", {
templateUrl : "templates/About.html",
controller: 'AboutCtrl',
resolve: resolveController(['controller/AboutCtrl'])
});
$routeProvider.otherwise('/home');
}]);
Your controllers should look like this.
define(['app'],function(app){
app.register.controller('HomeCtrl',['$scope',function($scope){
// Controller code goes here
}]);
});