I am having an issue using the ui-router with ionic tabs.
When I attempt to transition to a state that is nested within a tab from a separate tab it appears to resolve it in the stateProvider, in terms of entering the resolve statements, but never actually enters the state.
The applicable states are here:
.state('index', {
abstract: true,
templateUrl:'app/main.html',
controller: 'MainCtrl'
})
.state('index.got', {
url: "/got",
views: {
'got-tab': {
templateUrl: "app/got/main.html",
controller: 'GotCtrl'
}
}
})
.state('index.got.listing', {
url: "/listings/:id",
templateUrl: "app/got/listing/listing.html",
controller: "GotListingCtrl",
resolve: {
listing: function(Listing, $stateParams) {
return Listing.get({id: $stateParams.id});
}
},
})
.state('index.feed', {
url: "/feed",
views: {
'feed-tab': {
templateUrl: "app/home/feed/feed.html",
controller: 'FeedCtrl',
resolve: {
listings: function(CurrentUser) {
return CurrentUser.feed()
}
}
}
}
And the tabs
<ion-tabs class="tabs-striped tabs-color-positive tabs-icon-top">
<ion-tab title="Got" ui-sref="index.got.listings">
<ion-nav-view name="got-tab"></ion-nav-view>
</ion-tab>
<ion-tab title="Home" ui-sref="index.feed">
<ion-nav-view name="feed-tab"></ion-nav-view>
</ion-tab>
</ion-tabs>
The call I make to transfer states is
var index = $state.get('index')
$state.transitionTo('.got.listing', {id: '1'}, {relative: index})
I assume the issue is because I am dealing with nested names views, but any help would be much appreciated thanks
your resolves Should just be returning the Parameter Information for the current state, so for listing tab:
.state('index.got.listing', {
url: '/listings/:id,
templateUrl: '/app/got/listing/listing.html',
controller: 'GotListingCtrl',
resolve: {
listing: ['$stateParams', function($stateParams){
return $stateParams.id;
}]
}
})
Related
I am trying to create a custom controller to update the user profile.
I created the routing file and the corresponding controller.
Routing file: server/src/api/profile/routes/profile.js
module.exports = {
routes: [
{
method: 'GET',
path: '/profile',
handler: 'profile.getProfile',
},
{
method: 'PUT',
path: '/profile',
handler: 'profile.updateProfile',
},
]
}
Controller: src/api/profile/controllers/profile.js
async updateProfile(ctx) {
try {
const { id } = ctx.state?.user;
const user = strapi.query('admin::user').update({
where: { id },
data: {
username: "testUsername"
}
})
ctx.body = "User updated"
} catch(error) {
ctx.badRequest("Something went wrong", { error })
}
},
The above code returns "User updated", but the username does not update. I am executing the PUT call with a correct Bearer authorisation token and the user permissions for that user are set to enable "updateProfile".
Oddly enough, the same code, when changed to update a different API item, works perfectly fine:
async updateArticle(ctx) {
try {
const { id } = ctx.state?.user;
const article = strapi.query('api::article.article').update({
where: { author: id },
data: {
title: "New title"
}
})
ctx.body = article
} catch(error) {
ctx.badRequest("Something went wrong", { error })
}
},
I am also confused by different syntaxes appearing in the official Strapi documentation, for example some docs mention:
strapi.query('admin::user').update({ id }, data)
But in other places in the documentation its:
strapi.plugins['users-permissions'].services.user.update({ id });
And then elsewhere:
strapi.query('user', 'users-permissions').update(params, values);
Another question is: do I need to sanitise the input / output in any way? If yes, how? Importing sanitizeEntity from "Strapi-utils" doesn't work, but it's mentioned in several places on the internet.
Additionally, I cannot find a list of all ctx properties. Where can I read what is the difference between ctx.body and ctx.send?
The lack of good documentation is really hindering my development. Any help with this will be greatly appreciated.
I'm trying to get the data from database using an API, but there are no output on my vue controller.
Am I doing this right?
I think I'm assigning the scheduleList the wrong way.
I'm very new to vue.js and API, I want to know what I'm doing wrong here.
Controller
public function schedules(){
return Schedule::all();
}
api.php
Route::get('schedules', 'CalendarController#schedules');
Vue Component
<script>
import axios from 'axios'
export default {
data() {
return {
schedules: [],
scheduleList: [
{
id: schedules.id,
title: schedules.title,
category: schedules.category,
start: schedules.start,
end: schedules.end
},
],
};
},
methods: {
loadSchedules() {
axios.get('/api/schedules')
.then((response) => {
this.schedules = response.data;
})
}
},
mounted() {
this.loadSchedules();
}
};
</script>
<style>
</style>
The issue is in your data option because you're referencing schedules which is undefined, I'm sure that you're meaning this.schedules but doing that will not solve the issue because at first rendering this.schedules is an empty array, another problem that you're referencing at as object in scheduleList items using schedules.id, if the schedules property is an array i recommend the following solution :
<script>
import axios from 'axios'
export default {
data() {
return {
schedules: [],
scheduleList: [],
};
},
methods: {
loadSchedules() {
axios.get('/api/schedules')
.then((response) => {
this.schedules = response.data;
let schedule=this.schedules[0]
this.scheduleList.push({
id: schedule.id,
title: schedule.title,
category: schedule.category,
start: schedule.start,
end: schedule.end
})
})
}
},
mounted() {
this.loadSchedules();
}
};
</script>
always catch errors if you do promises.
loadSchedules() {
axios.get('/api/schedules')
.then((response) => {
this.schedules = response.data;
})
.catch(error => {
console.log(error)
})
inside your error you can better see whats going wrong.
other way is the "network" tab in your browser where you can trace your api request
I have a project that requires parent routes that are separated, in order to isolate URLs, controllers and API calls.
/boardgames/:id/review/
/boardgames/:id/setup/
The issue I am trying to solve is how to have a common child route, for all of the parent routes?
/boardgames/:id/review/rules/
/boardgames/:id/setup/rules/
Here is a simplified version of the current UI-Router config:
.state('app.frontend.view', {
abstract: true,
url: '/boardgames/:id',
views: {
'page#': {
templateUrl: 'public/html/game/view/index.html',
resolve: {},
controller: 'View'
}
}
})
.state('app.frontend.view.review', {
url: '/review/',
views: {
'tab#app.frontend.view': {
templateUrl: 'public/html/game/tabs/review/index.html',
resolve: {},
controller: 'ViewReview'
}
}
})
.state('app.frontend.view.setup', {
url: '/setup/',
views: {
'tab#app.frontend.view': {
templateUrl: 'public/html/game/tabs/setup/index.html',
resolve: {},
controller: 'ViewSetup'
}
}
});
Here is the HTML structure: (public/html/game/view/index.html)
<div class='item'>
<div ui-view='tab'></div>
</div>
ALL IS WORKING UP TO THIS POINT.
I was thinking of passing another parameter to create a dynamic state... and then chaining the child route:
.state('app.frontend.view.{{:path}}', {
url: '/:path/',
views: {
'tab#app.frontend.view': {
templateUrl: 'public/html/game/tabs/:path/index.html',
resolve: {},
controller: ':path' (format :path into friendly name)
}
}
})
.state('app.frontend.view.{{:path}}.rules', {
url: '/rules/',
views: {
'rules#app.frontend.view': {
templateUrl: 'public/html/game/tabs/rules/index.html',
resolve: {},
controller: 'ViewRules'
}
}
});
Is this the best way to go forward?
After researching this topic further, I found that:
State naming should be locked in during the config phase.
.state('app.frontend.view.{{:path}}', {}
Would equal:
.state('app.frontend.view.image', {}
The Url would include the parameter '/:path/, templateUrl and controller can all have locked in names and use the parameter differently:
In the router resolve it would be:
resolve: {
tabResolve: ['$stateParams', 'game', function($stateParams, game) {
return game.show({
id: $stateParams.id,
tab: $stateParams.tab
}).$promise;
}]
}
Only one controller is needed now, since the data being passed in is different for every parameter (review, setup).
$state.go isn't transitioning to default.settings.customization but instead its going to our 'main frontpage' default.feed
I think it has to do with the resolve, since when I change var state to a different state, it works just fine.
app.config(['$stateProvider', function($stateProvider) {
$stateProvider
.state('default.settings.customization', {
url: '/settings/customization',
templateUrl: 'app/settings/customization/customization.html',
controller: 'CustomizationCtrl',
auth: {
authorizedRoles: ['admin']
},
resolve: {
customization: [
'CustomizationService',
function(CustomizationService) {
return CustomizationService.get().then(function(res) {
return res.data;
});
}
]
}
});
}]);
Test:
var state = 'default.settings.customization';
it('should resolve data', function() {
customizationServiceMock.get = jasmine.createSpy('customizationServiceMockGet')
.and.returnValue(apiResp.accountCustomization);
$state.go(state);
$rootScope.$apply();
expect($state.current.name).toBe(state);
});
LOG:
PhantomJS 1.9.8 (Linux) app/settings/customization router should resolve data FAILED
Expected 'default.feed' to be 'default.settings.customization'.
Error: Expected 'default.feed' to be 'default.settings.customization'.
I think it's related to your spy function, check that apiResp is available in your scope. I had a similary problem, I used $q to return a promise in my spy function but $q was not injected.
I created two json files where I'm getting the data through a controller homeCtrl and articleCtrl. Than I have a state to display all my data places and articles
.state('overview', {
abstract: true,
url: '/overview',
templateUrl: '_/partial/overview/overview.html',
controller: 'homeCtrl',
resolve: {
places: ['$http', function($http) {
return $http.get('_/api/place.json').then(function(response) {
return response.data;
})
}]
}
})
.state('overview.all', {
url: '/all',
templateUrl: '_/partial/overview/overview-all.html',
controller: 'homeCtrl',
resolve: {
places: ['$http', function($http) {
return $http.get('_/api/place.json').then(function(response) {
return response.data;
})
}]
}
})
.state('overview.articles', {
url: '/articles',
templateUrl: '_/partial/overview/overview-articles.html',
controller: 'articleCtrl',
resolve: {
articles: ['$http', function($http) {
return $http.get('_/api/article.json').then(function(response) {
return response.data;
})
}]
}
})
Afterwards I created two states to get the data by id
.state('overview.detail-place', {
url: '/:id/place',
templateUrl: '_/partial/details/detail-place.html',
controller: function($scope, $stateParams){
$scope.place = $scope.places[$stateParams.id];
}
})
.state('overview.detail-article', {
url: '/:id/article',
templateUrl: '_/partial/details/detail-article.html',
controller: function($scope, $stateParams){
$scope.article = $scope.articles[$stateParams.id];
}
})
I have no problem going to the detail page of a place but when I want to go to an article I get this error, 99 being the id of the article.
TypeError: Cannot read property '99' of undefined
at new $stateProvider.state.state.state.state.state.state.state.state.controller (http://localhost:8888/%203.0v/_/js/app.js:86:53)
at d (http://localhost:8888/%203.0v/_/lib/angular.min.js:34:265)
at Object.instantiate (http://localhost:8888/%203.0v/_/lib/angular.min.js:34:394)
at http://localhost:8888/%203.0v/_/lib/angular.min.js:66:112
at http://localhost:8888/%203.0v/_/lib/angular-ui-router.min.js:7:15323
at J (http://localhost:8888/%203.0v/_/lib/angular.min.js:53:345)
at f (http://localhost:8888/%203.0v/_/lib/angular.min.js:46:399)
at http://localhost:8888/%203.0v/_/lib/angular.min.js:46:67
at j (http://localhost:8888/%203.0v/_/lib/angular-ui-router.min.js:7:14566)
at http://localhost:8888/%203.0v/_/lib/angular-ui-router.min.js:7:14835 <div class="main-container overview ng-scope" ui-view="">
The issue here is, that state 'overview.articles' does initiate the articles collection
.state('overview.articles', {
...
controller: 'articleCtrl',
resolve: {
articles: ....
So most- likely the 'articleCtrl' does place the articles into the $scope.articles.
BUT, this state: 'overview.detail-article' in fact does not have access to that collection:
.state('overview.detail-article', {
...
controller: function($scope, $stateParams){
$scope.article = $scope.articles[$stateParams.id];
}
And why? because the 'overview.detail-article' is not child state of the 'overview.articles'
But this still does not have to be enough with ui-router, check this:
Scope Inheritance by View Hierarchy Only (small cite:)
Keep in mind that scope properties only inherit down the state chain if the views of your states are nested. Inheritance of scope properties has nothing to do with the nesting of your states and everything to do with the nesting of your views (templates).
It is entirely possible that you have nested states whose templates populate ui-views at various non-nested locations within your site. In this scenario you cannot expect to access the scope variables of parent state views within the views of children states.
So we need the detail state to be a child of articles and also nested in the parent view:
.state('overview.articles.detail-article', { ...
A plunker with working example...