So here's the relevant segment from my router:
app.js
.state('app.browse', {
url: "/browse/:question",
controller: 'QCtrl',
resolve: {
question: function($stateParams, qService){
console.log(qService.getQuestion($stateParams.question).q);
return qService.getQuestion($stateParams.question).q;
}
},
views: {
'menuContent': {
templateUrl: "templates/browse.html"
}
}
})
/* QSERVICE HERE */
.factory('qService', function() {
var questions = [ {'q': "text text"} ];
return {
questions: questions,
getQuestion: function(index) {
return questions[index]
}
}
})
controllers.js
.controller('QCtrl', function($scope, question){
$scope.questions = qService.questions;
$scope.question = question;
})
Which finds exactly what I'm looking for as demonstrated by the console log.
However in my browser view, I am unable to grab the question variable!
browser.html
<ion-view view-title="Browse">
{{question}}
</ion-content>
Which always displays as empty! Why is this happening, and how do I resolve it?
Resolve will not bind question unto your controller.
In your controller do this
.controller('QCtrl', function ($scope, question) {
$scope.question = question;
})
In addition - in your state object, the question is being passed incorrectly. Correction:
.state('app.browse', {
url: "/browse/:question",
resolve: {
question: function($stateParams, qService){
return qService.getQuestion($stateParams.question);
}
},
views: {
'menuContent': {
templateUrl: "templates/browse.html",
controller: 'QCtrl',
}
}
})
You're also missing templateUrl in your state object. Update this to reflect where the the template is and it should be good to go :)
Related
I have this plunkr. I define two controllers: mainController and itemsController. I want to access to the scope variable items from a view, but I can't.
To reproduce, you need to click first in the button Populate Items, (the array item is populated from a service) and you see in the console the values. Then click in the button Say Hello ! and then you will see that items is empty; but, the variable tab is being accessed.
I think that I'm not applying in the correct way the definitions of the controllers.
There is updated and working plunker
What we need, is the data sharing:
How do I share $scope data between states in angularjs ui-router?
so instead of this
app.controller("itemsController",
function($rootScope, $scope, $state, $stateParams, Data) {
$scope.items = []; // local reference, not shared
$scope.getFromJson = function() {
Data.get().then(function handleResolve(resp) {
$scope.items = resp;
console.log($scope.items);
});
};
})
we will fill the shared reference $scope.Model.items = resp;
app.controller("itemsController",
function($rootScope, $scope, $state, $stateParams, Data) {
$scope.getFromJson = function() {
Data.get().then(function handleResolve(resp) {
$scope.Model.items = resp;
console.log($scope.Model.items);
});
};
})
which will be hooked on the super root home. So, instead of this:
$stateProvider
.state("home", {
abtract: true,
url: "/home",
resolve: {
$title: function() {
return 'Tab1';
}
},
views: {
"viewA": {
templateUrl: "home.html"
}
}
});
we will have that:
.state("home", {
abtract: true,
url: "/home",
resolve: {
$title: function() {
return 'Tab1';
}
},
views: {
"viewA": {
templateUrl: "home.html",
// HERE we do the magic
// this is a super parent view
// at which $scope we will have shared reference Model
controller: function($scope){
$scope.Model = {}
}
}
}
});
check it in action here
I am using the AngularJS framework (as well as its ui-router), and I am having a hard time getting my data to resolve the way I want. I will give an example below of what I am trying to do:
$stateProvider
.state('home',{
views: {
'test': {
templateUrl: 'test.html',
resolve: {
config: function() {
var result = /*service call that returns json*/
return result;
}
}
controller: function($scope, config){
console.log(config);
}
},
'test': {
templateUrl: 'test.html',
resolve: {
config: function() {
var result = /*service call that returns DIFFERENT json*/
return result;
}
}
controller: function($scope, config){
console.log(config);
}
}
}
})
<div ui-view="test">
<div ui-view="test">
Is there any way in which to uniqely assign and inject 'config' into the controller so that it contains the json that its respective service call returned? The idea here is I want the same template but with different configs coming into them (scoped to that particular view). Right now, config just contains the last resolve that was executed.
I hope I am not confusing. Let me know if you need any clarifications...Much appreciated!
The views need to be named differently and so do the resolves. Using the same template for both of them is not an issue. Lastly, the resolve has to be relative to the state, not the views.
$stateProvider
.state('home',{
views: {
'test': {
templateUrl: 'test.html',
controller: function($scope, config){
console.log(config);
}
},
'test2': {
templateUrl: 'test.html',
controller: function($scope, config2){
console.log(config2);
}
}
},
resolve: {
config: function() {
var result = /*service call that returns json*/
return result;
},
config2: function() {
var result = /*service call that returns DIFFERENT json*/
return result;
}
}
})
<div ui-view="test">
<div ui-view="test2">
What I am trying to do is within the Search controller, once I get the search results back from the server ($http) change view to a different view - the search results view. I am not sure if the approach I am going about it is right, but either-way it doesn't seem to be working. I will need to pass the response as well, so the new view can display the results/response.
My app.js:
.....state('tab.search', {
url: '/search',
views: {
'tab-search': {
templateUrl: 'templates/tab-search.html',
controller: 'SearchCtrl as search'
}
}
})
.state('tab.search-results', {
url: '/results',
views: {
'tab-search-results': {
templateUrl: 'templates/tab-search-results.html',
controller: 'SearchResultsCtrl as searchResults'
}
}
})
Then my search controller has:
.controller('SearchCtrl', function($scope, $state, $location, $ionicPopup, service) {
....
$scope.doSearch = function(state) {
.....
var result = service.doSearch(dataObj);
result.then(function(response) {
console.log("I'm here");
$state.go('tab.search-results');
......
My search results view (tab-search-results.html) has the following basic code at the moment:
<ion-view view-title="Search Results">
<ion-content padding="true">
hello world
</ion-content>
</ion-view>
This basic structure is how all my other pages/views are setup too.
What happens when I perform the search is that the console message gets outputted, and then the URL changes to /results as per the tab.search-results state, but the template/view doesn't change/show.
Interestingly if I change $state.go('tab.search-results'); to point to another app state/view that I know works, it works perfectly - but for whatever reason this state/view isn't working.
Also, if there is a better way of achieving this same thing, then please let me know. I will be needing to eventually pass the "response" from SearchCtrl to SearchResultsCtrl - or rather access it on the search results page in one form or another.
Many thanks.
I think you are looking for $stateParams.
var result = service.doSearch(dataObj);
result.then(function(response) {
$state.go('tab.search-results', {'searchData':response});
}
In your routes file:
.state('tab.search-results', {
url: '/results/:searchData',
views: {
'tab-search-results': {
templateUrl: 'templates/tab-search-results.html',
controller: 'SearchResultsCtrl as searchResults'
}
}
})
And in your SearchResultsCtrl:
.controller($stateParams) {
console.log($stateParams.searchData) // will give you search results
}
NOTE:If you don't want to pass data through the URL you can use params key in the .state() method.
.state('tab.search-results', {
url: '/results',
params: {
'searchData':null
},
views: {
'tab-search-results': {
templateUrl: 'templates/tab-search-results.html',
controller: 'SearchResultsCtrl as searchResults'
}
}
})
I realised why my view wasn't changing properly. The fix was changing the views in the sub-view to reference the parent view.
Fail (sub-view has unique name from parent):
.....state('tab.search', {
url: '/search',
views: {
'tab-search': {
templateUrl: 'templates/tab-search.html',
controller: 'SearchCtrl as search'
}
}
})
.state('tab.search-results', {
url: '/results',
views: {
'tab-search-results': {
templateUrl: 'templates/tab-search-results.html',
controller: 'SearchResultsCtrl as searchResults'
}
}
})
Success (sub-view references parent, 'tab-search'):
.....state('tab.search', {
url: '/search',
views: {
'tab-search': {
templateUrl: 'templates/tab-search.html',
controller: 'SearchCtrl as search'
}
}
})
.state('tab.search-results', {
url: '/results',
views: {
'tab-search': {
templateUrl: 'templates/tab-search-results.html',
controller: 'SearchResultsCtrl as searchResults'
}
}
})
Thanks all, I think I worked out the problem. It was putting the search results page under the tab abstract state. eg: tab.search-results rather than search-results - I am guessing this was the problem as there is no search results tab. When I re-named the state to just search-results (and modified the $state.go to use 'search-results' instead of 'tab.search-results') it worked. Does this seem right?
I'm running out of idea right now. Everything seems fine, but when Im trying to inherit master data into the details view nothing really shows when I consoled except for the id.
Console Output : Object {id: "78"}
Here's my code :
Config
.state('app.home', {
url: "/home",
views: {
'menuContent': {
templateUrl: "templates/home.html",
controller: 'PostHomeCtrl'
}
}})
.state('app.posthome', {
url: "/home/:id",
views: {
'menuContent': {
templateUrl: 'templates/post.html',
controller: 'PostDetailCtrl'
}
}})
Factory
.factory('Posts', function($http){
var blogs = []; //Private Variable
return {
GetBlog: function(){
return $http.get('path/to/resources').then(function(response){
blogs = response;
return response;
});
},
GetPost: function(postId){
for(i=0;i<blogs.length;i++){
if(blogs[i].id == postId){
return blogs[i];
}
}
return null;
}
}})
Controller
.controller('PostHomeCtrl', function(Posts, $scope){
Posts.GetBlog().then(function(blogs){
$scope.blogs = blogs.data;
console.log(blogs.data);
});
})
.controller('PostDetailCtrl', function(Posts, $stateParams, $scope){
var postId = $stateParams;
$scope.blog = Posts.GetPost(postId);
console.log(postId);
});
nvm just figured it out, turns out my I forgot to add .data at my blog = response . So it becomes blog=response.data instead of blog=response. Thanks
I'm trying to test an Angular UI Bootstrap modal that is being called from the onEnter of the following state:
.state("profile.index.edit.services", {
url: "/edit/services/:serviceCode",
parent:"profile.index",
onEnter: ['$stateParams', '$state', '$modal',function($stateParams, $state, $modal) {
$modal.open({
templateUrl: 'profile/edit-services-modal.html',
controller: 'ProfileEditServicesController',
resolve: {
profileData: function(CacheService){
return CacheService.getItem(CacheService.Items.Profile.loadedProfile);
},
allServicesList: function(ProfileService){
return ProfileService.getAllServicesList($stateParams.serviceCode,$stateParams.orgId);
},
serviceCode: function() {
return $stateParams.serviceCode;
}
}
}).result.then(function(result) {
if (result) {
return $state.transitionTo("profile.index", { orgId: $stateParams.orgId });
}
else { // cancel
return $state.transitionTo("profile.index", { orgId: $stateParams.orgId }); // don't reload
}
}, function () {
// executes on close/cancel/ESC
return $state.transitionTo("profile.index", { orgId: $stateParams.orgId });
});
}]
})
I've been banging my ahead against this trying many different things to set the test up, but can't seem to figure it out. Any plunkers or suggestions are greatly appreciated!!!!
By the way, the state above is a descendant of these states, which I've been able to write tests for that pass:
.state('profile.index', {
url: '/:orgId',
views: {
'profile-index#profile': {
templateUrl: 'profile/view-profile.html',
controller: 'ProfileController'
},
'header#': {
templateUrl: 'common/layout/header.html',
controller: 'HeaderController'
},
'footer#':{
templateUrl: 'common/layout/footer.html',
controller: 'FooterController'
}
},
resolve: {
profileData: function(ProfileService, $stateParams){
return ProfileService.getProfile($stateParams.orgId, true);
}
}
})
.state('profile.index.edit', {
url: '',
abstract: true
})
did you ever figure this out? you should have passed a named controller, that way you could test that controller (since it would just be a function) directly instead of relying on onEnter being fired.