how to dynamically set templateUrl in ionic tabs? - angularjs

Is it possible to pass a templateUrl parameter to the .state tab definitions similar to the following? I have multiple different pages to write and don't want a bunch of nested ng-ifs within a single template to parse out which "html" page to show:
.state('tab.menu', {
url: '/menu',
views: {
'tab-menu': {
templateUrl: 'templates/tab-menu.html',
controller: 'MenuCtrl'
}
}
})
.state('tab.menu-detail', {
url: '/menus/:menuID',
views: {
'tab-menu': {
templateUrl: function($stateParams,Menus) {
console.log("In function") ;
console.log("Template: " + Menus.get($stateParams.menuID).url) ;
return 'templates/' + Menus.get($stateParams.menuID).url ;
},
controller: 'MenuSubCtrl'
}
}
})
// controllers
.controller('MenuCtrl', function($scope,Menus) {
$scope.menus = Menus.all() ;
})
.controller('MenuSubCtrl', function($scope,$stateParams,Menus) {
$scope.menu = Menus.get($stateParams.menuID);
})
// services
.factory('Menus', function() {
var menus = [
{name:"Account",url:"menu-account.html",menuID:0},
{name:"Contact",url:"menu-contact.html",menuID:1},
{name:"Help",url:"menu-help.html",menuID:2},
{name:"Privacy",url:"menu-privacy.html",menuID:3},
{name:"Rate App",url:"menu-rate.html",menuID:4},
{name:"Report Bugs",url:"menu-bugs.html",menuID:5},
{name:"Settings",url:"menu-settings.html",menuID:6}
] ;
return {
all: function() {
return menus ;
},
get: function(menu) {
for (var i = 0; i < menus.length; i++) {
if (menus[i].menuID === parseInt(menuID)) {
return menus[i];
}
}
return null;
},
} ;
}) ;
In the above .state('tab.menu-detail'..., the templuateUrl function fires and the first console log entry works, the 2nd one does nothing, no message, no error...nothing. It just stops. I have tried multiple iterations to get this to work and am at a complete loss. When I click the above Tab page link (which is supposed to take you to a sub-custom view) it does nothing. No console message, no error...nothing.

You can assign function to template Url. I have faced the similar scenario following solution worked fine.
check this:
link

Related

How to supply the separate `template` when param exist?

I have a scenario, to handle the params. ( when param exist it will handled differently )
so, how can i keep 2 templates and use them according to the requirement? at present I am trying like this, which is not working at all.
any one help me?
my state with 2 template: ( please help me to correct )
.state('serialCreateCase', {
url: '/serialCreateCase?sn=',
views:{
"" : {
"templateUrl": 'app/login/loginWithSerial.html'
},
"?sn=" : {
"templateUrl": 'app/login/login.html'
}
}
})
here is the redirection with 2 scenarios: ( correct me if I am wrong )
if(!$rootScope.isUserLoggedIn && toParams.sn !== undefined ) {
console.log('dont take action', toState, toParams.sn );
$rootScope.canNavigate = true;
$state.go('serialCreateCase'); //works
$state.go('serialCreateCase', {sn:'1234'}); //not works
event.preventDefault();
return;
}
There is a working plunker
I would say that you need replace templateUrl with
Templates
TemplateUrl ...
templateUrl can also be a function that returns a url. It takes one preset parameter, stateParams, which is NOT
injected.
TemplateProvider
Or you can use a template provider function which can be injected, has access to locals, and must return template HTML,
like this...
There are more details and plunkers
Angular UI Router: decide child state template on the basis of parent resolved object
dynamic change of templateUrl in ui-router from one state to another
This I prefer the most
...
templateProvider: [$stateParams, '$templateRequest',
function($stateParams, templateRequest)
{
var tplName = "pages/" + $stateParams.type + ".html";
return templateRequest(tplName);
}
],
(check it here) because it uses also $templateRequest
EXTEND
There is a working plunker
this could be the state def
.state('serialCreateCase', {
url: '/serialCreateCase?sn',
views: {
"": {
templateProvider: ['$stateParams', '$templateRequest',
function($stateParams, templateRequest) {
var tplName = "app/login/loginWithSerial.html";
if($stateParams.sn){
tplName = "app/login/login.html";
}
return templateRequest(tplName);
}
]
},
}
});
what we really need is to always pass some value, as sn. So, these should be the calls:
// we need to pass some value, to be sure that there will be other than last
<a ui-sref="serialCreateCase({sn: null})">
// here is reasonable value
<a ui-sref="serialCreateCase({sn:'1234'})">
Check it here in action
use, $stateParams instead of toParams,
1) Deciding the template depending on the param(your requirement)
.state('serialCreateCase', {
url: '/serialCreateCase?sn=',
views: {
'': {
templateUrl: function(stateParams) {
var param = stateParams.sn
return (param == undefined) ? 'app/login/loginWithSerial.html' : 'app/login/login.html'
},
controller: 'myController',
}
}
})
You can check the stateParam using the parameter of templateUrl, and change the templates.
2) change the state depending on the param from controller.
This is a sample controller where you can check the state parameter and use the re directions as your wish.
allControllers.controller('myController', ['$scope','$rootScope','$state','$stateParams',
function($scope,$rootScope,$state,$stateParams) {
if(!$rootScope.isUserLoggedIn)
{
if($stateParams.sn !== undefined )
{
alert('dont take action', $stateParams.sn );
}
else
{
alert('You can redirect, no parameter present');
}
}
}
}])

Setting multiple controllers in one state, IONIC

I want to check if there is a user signed in, for it to redirect to another page, if there is no user, i want to redirect to the homePage. The home page has a controller called storeCtrl.
I tried this:
.state('homePage',
{
url: '/homePage',
templateUrl: 'templates/homePage/homePage.html',
controller:'storeCtrl',
function ($localStorage,$state) {
if ($localStorage.user) {
$state.go('tabs.profile');
} else {
$state.go('homePage');
}
}
})
but it doesn't work. I tried this also:
.state('homePage',
{
url: '/homePage',
templateUrl: 'templates/homePage/homePage.html',
controller:
function ($localStorage,$state) {
if ($localStorage.user) {
$state.go('tabs.profile');
} else {
$state.go('homePage'),
controller:storeCtrl
}
}
})
but that also didn't work.
instead of putting it in the state. try to add this inside app.run
app.run(function($ionicPlatform,$state,$rootScope,$localStorage) {
$ionicPlatform.ready(function() {
//your code
})
$rootScope.$on('$stateChangeStart', function (event,next, nextParams, fromState,fromParams) {
var nextScreen=next.name;
if (nextScreen!="homePage" && $localStorage.user===undefined) {
event.preventDefault();
$state.go('homePage');
return;
}
});
})

How to reset $stateparam parameter value to null in angularjs?

This is my code.
.state('appSetting.studentList', { url: '/student', views: { 'list#appSetting': { templateUrl: appUrl + '/Student/List', controller: 'StudentCtrl' } } })
.state('appSetting.studentList.details', { url: '/:studentId', views: { 'details#appSetting': { templateUrl: appUrl + '/Student/Edit', controller: 'StudentEditCtrl' } } })
.state('appSetting.employeeList', { url: '/employee', views: { 'list#appSetting': { templateUrl: appUrl + '/Employee/List', controller: 'EmployeeCtrl' } } })
.state('appSetting.employeeList.details', { url: '/:employeeId', views: { 'details#appSetting': { templateUrl: appUrl + '/Employee/Edit', controller: 'EmployeeEditCtrl' } } })
I have a add button on layout , when user click the add button call the following function.
$scope.gotoAdd = function () {
if ($state.current.name.indexOf(".details") == -1) {
$state.go($state.current.name + ".details")
}
else {
var paramId = $state.current.url.slice(2);
$state.go($state.current.name, ({ studentId: "", reload: true }));
}
};
In the above code working fine, but when open employee page user click add button i want to empty of employeeId parameter. I have number of links so if condition is using lengthy process. The above variable paramId dynamically changed (one time "studentId" , "employeeId" ,..............) depends on current state.
I tried the following code but not working because paramId contains string value
$state.go($state.current.name, ({ paramId: "", reload: true }));
Why are you putting the second parameter in '( )' in $state.go().
Try
$state.go($state.current.next, {}, {reload: true});
or
$state.go($state.current.next, {paramId: ""}, {reload: true});
$scope.gotoAdd = function () {
if ($state.current.name.indexOf(".details") == -1) {
$state.go($state.current.name + ".details")
}
else {
for (var prop in $stateParams) {
if ($stateParams.hasOwnProperty(prop)) {
$stateParams[prop] = '';
}
}
$state.go($state.current.name,$stateParams, { reload: true });
}
};
$state.go can take an inherit boolean parameter that serve exactly for this purpose.
As of UI router 0.2.15 -probably an old version, the documentation states
inherit - {boolean=true}, If true will inherit url parameters from current url.
In fact, it reset not only url parameters, but all $stateParams to their default, like what they are in state definition.
This will keep only state params as passed through the params object and all other are set to default or deleted.
$state.go('target.state', params, {inherit: false});

How to pass data between views using stateParameters (not routes) in AngularJS

I have some views in my applications, and I have hard time to show the data when moving from one view to another.
I have a list of news and when I click on the particular news I want the view for that particular news to be shown. Here is my code:
My app.js :
.state('app.list', {
url: "/list",
views: {
'appScreen': {
templateUrl: "list.html",
controller: 'List.Ctrl'
}
}
})
.state('app.singleview', {
url: "/list/:newsId",
views: {
'appScreen': {
templateUrl: "single.html",
controller: 'SingleCtrl'
}
}
})
My controllers:
ListCtrl.$inject = ['$http', '$scope', 'datacontext'];
function ListCtrl( $http, $scope, datacontext) {
$scope.list = [];
datacontext.getPosts().then(function (posts) {
console.log('posts', posts);
$scope.list= posts;
}, function(reason) {
alert(reason);
});
The following controller is the one which will show me the single news and I have written some code but is not correct. In the URL I get the ID but I can't manage to show the data for that ID.
SingleCtrl.$inject = ['$scope', '$stateParams', 'datacontext'];
function ListNewCtrl($scope, $stateParams, datacontext) {
$scope.New = getNewsById($stateParams.newsId);
function getNewsById(id) {
datacontext.getPosts().then(function(posts) {
var found = null;
for (var i = 0; i < posts.length; i++) {
if (posts[i].id == id) {
found = posts[i];
break;
}
}
return found;
})
}
};
So in this controller what I am trying to do is get the ID and match it with postsId, and then show the data accordingly but it does no seem to work
You're confused with the asynchronism. The code should be
getNewsById($stateParams.newsId);
function getNewsById(id) {
datacontext.getPosts().then(function(posts) {
var found = null;
for (var i = 0; i < posts.length; i++) {
if (posts[i].id == id) {
$scope.New = posts[i];
break;
}
}
});
}
So that, when the success callback is executed, the New scope variable is initialized by the found post.
That said, I have a hard time understanding why you're getting a whole list of posts from the backend instead of using a REST service returning a single post by ID. If you did, it would be reduced to
function getNewsById(id) {
datacontext.getPost(id).then(function(post) {
$scope.New = post;
});
}

How can I automatically go to the last selected child state when I view only the parent state with ui-router?

I have the following set up:
var admin = {
name: 'admin',
url: '/admin',
views: {
'menu': {
templateUrl: '/Content/app/admin/partials/menu.html',
},
'content': {
templateUrl: function (stateParams) {
var content = localStorage.getItem('ls.adminPage');
if (content != null && content != "") {
return '/Content/app/admin/partials/' + content + '.html';
} else {
return '/Content/app/common/partials/empty.html';
}
}
}
}
};
var adminContent = {
name: 'admin.content',
parent: 'admin',
url: '/:content',
views: {
'content#': {
templateUrl: function (stateParams) {
localStorage.setItem('ls.adminPage', stateParams.content);
return '/Content/app/admin/partials/' + stateParams.content + '.html';
},
}
}
}
What happens is that when a user has previously been to the /admin/xxx page then the next time /admin is selected it will again return the /admin/xxx page.
However visually this is a mess as the browser URL shows as /admin and the state is not set correctly.
Is there some way I can store away a child state and then have it so that when the user browses to the parent that it will transition to the last known child state and have that URL show in the browswer ?
Do this:
myapp.config(function($urlRouterProvider){
$urlRouterProvider.when('/admin', function() {
var content = localStorage.getItem('ls.adminpage');
if ( content != null && content != "" ) {
return "/admin/" + content;
}
else {
return false;
}
});
});
See this plunkr: http://plnkr.co/edit/oEXZpO
Edit: Revisiting this answer after two months I realize that it is a little short (to say the least) on explanation: So this will actually "redirect" the request to the last selected admin page so that it will show up in the URL. I have updated the Plunkr and added a function to show the current document URL. So one can see that after clicking on /admin/ the URL will actually be /admin/12345 if this was the admin sub page visited before.

Resources