Routing in AngularJS with variable in the beginning of the URL - rest

I'm experiencing some behavior that I can't explain, but I'm sure somebody else can. I'm setting up my app module like so:
var appmodule = angular.module('appmodule', ['ui']).config(
['$routeProvider', function($routeProvider) {
$routeProvider.
when('/dashboard', {
templateUrl: 'partials/dashboard.html',
controller: dashCtr,
layer: 'main'
}).
when('/:campaignId/edit', {
templateUrl: 'partials/edit.html',
controller: campaignCtr,
layer: 'layer1'
}).
when('/:campaignId', {
templateUrl: 'partials/campaign_info.html',
controller: campaignCtr,
layer: 'layer1'
}).
when('/inbox', {
templateUrl: 'partials/inbox.html',
controller: inboxCtr,
layer: 'main'
}).
otherwise({redirectTo: '/dashboard'});
}]);
When I navigate to app.com/:campaignId or app.com/:campaignId/edit, all works as expected, but if I try app.com/inbox (or anything else), I get redirected back to /dashboard. I've read in a few other places a URL can't begin with a variable, but I'm new to this concept (usually just to design side of the front-end) and don't understand why.
Thanks.

Well it is simply because inbox route is below ''/:campaignId' route. Angular checks rules in the order they were defined, and ''/:campaignId' rule is matching every single url, so there is no chance to get to 'inbox' route.
Just define '/:campaign' routes after all other routes and everything should be working.

Related

ngOnChange only triggers after clicked somewhere on the screen after subscribe

I have the following components.
Parent:
#Component({
selector: 'test'
})
onAccountChange(account: AccountItem): void {
this.appService.callApi.subscribe((data) => {
this.availableInstrument = data
})
}
And my Child component is as follows:
#Component({
selector: 'child'
})
export class Child implements OnInit, OnChanges {
#Input('availableInstrument') availableInstrument!: any[]
ngOnChanges() :void {
console.log("Change")
this.initializeComponent()
}
My question is at I notice that the ngOnChange function only gets called after I click somewhere else on the screen, even though the callback function (onAccountChange) has completed and availableInstrument has been populated from the api call. I would want the ngOnChange function be called as soon as the input data is changed from the api call rather than having to click somewhere else on the screen. If I hard code the input values in my call back function, I see ngOnChange is called immediately in the child component, but not when it is within the subscribe block.
Thank you so much!
You need to set the change detection strategy to onPush.
#Component({
selector: "child",
changeDetection: ChangeDetectionStrategy.OnPush
})

ion-view cache & states with URL Parameters

The cache mechanism of the ion-views seems broken when using URL Parameters in the view.
$stateProvider.
.state('a', {
url: '/a',
templateUrl: 'templates/a.html',
controller: 'ACtrl'
})
.state('b', {
url: '/b/:id',
templateUrl: 'templates/b.html',
controller: 'BCtrl'
})
In this example the state 'a' is cached and works as expected. But the state 'b' is just cached if the same id appears twice. So /b/1 and /b/2 results in different ion-view dom elements.
I would expect that the same ion-view dom element is used for all calls to /b/:id.
Is this a bug or works as expected? In my situation I want the "other" behaviour, any idea how to archive this?
You can try this to delete the ui-routing cache.
.run(function($ionicPlatform,$rootScope,$templateCache) {
$rootScope.$on('$viewContentLoaded', function() {
$templateCache.removeAll();
});
})
Worked for me.

Ionic: reloading current child state from side menu causes loss of header

I'm creating a simple Ionic menu app and I would like to reload the current state from the side menu.Here's a Plunkr to illustrate the problem.
In the 'Search' state, the current time is displayed. The desired behavior is the following: when I click 'Search' from the side menu, the time is refreshed, i.e. the controller is reloaded. This should happen even when I'm already on the Search page. In reality, the controller is of course much more complex, but this example is enough to illustrate the problem.
I started from the ionic 'menu' starter template. To be able to reload the state, I changed two things:
disabled view caching in app.js config function: $ionicConfigProvider.views.maxCache(0);
In menu.html, I'm passing ui-sref-opts to explicitly reload the state:
ui-sref="app.search" ui-sref-opts="{reload: true}"
The result is that the time is indeed updated, however, the header of the view is gone.
Any suggestions as to what I'm doing wrong?
try something like this in the routing:
.state('tab.home', {
url: '/home',
cache: false, //<-- FORCE TO CLEAR CACHE
views: {
'tab-home': {
templateUrl: 'templates/home/home.html',
controller: 'HomeController'
}
}
})
You can broadcast an event to achieve that. But if you want to keep it like that, you could use a parameter and it would be all right because basically the one in control of the date var is your menu and not your state.
So you could do this:
app.js
.state('app.search', {
url: "/search",
params:{
date: new Date()
},
views: {
'menuContent' :{
templateUrl: "search.html",
controller: 'SearchCtrl'
}
}
})
Menu item
<ion-item nav-clear menu-close ui-sref="app.search({date: updateDate()})">
Search
</ion-item>
controllers.js (App controller or specific menu controller)
.controller('AppCtrl', function($scope) {
$scope.updateDate = updateDate;
function updateDate(){
return new Date();
}
})
controllers.js
.controller('SearchCtrl', function($scope, $stateParams) {
$scope.now = $stateParams.date;
})

Non functioning default policy in SailsJS

I'm trying to implement the basic Passport integration in SailsJS. In my policies.js file, I have the default settings that every tutorial mentions.
'*': ['passport', 'sessionAuth'],
'auth': {
'*': ['passport']
}
My issue is that going to the main page localhost:1337/ doesn't seem to get passed through either policy. If I just set false there, everything still works. If I set false on the auth object for '*' though, I will get Forbidden on any /auth/* route. So, the policies seem to work, I just don't understand why the default catch-all doesn't. Thanks.
Do you use a controller or do you directly serve a view like in the sample homepage?
If you are serving the view directly with something similar to this:
// in config/routes.js
module.exports.routes = {
'/': {
view: 'homepage'
}
}
then you will have to modify it and use a controller in order to te able to use policies.
Create a route to a controller instead of a view:
// in config/routes.js
module.exports.routes = {
// Delete the previous definition and declare a route
// to a controller "index"
'get /': 'indexController.home'
}
Create the controller:
// in api/controllers/IndexController.js
module.exports = {
home: function (req, res) {
// Render the view located in "views/homepage.ejs"
res.view('homepage');
}
};
Then you will be able to manage the policies to apply to the controller index in the file config/policies.js.

SailsJS Policy based route with a view

I'm trying to use the routes.js to define a route to '/account'.
I want whoever is trying to access that path to go through the UserController and the checkLogin action and if the security check passes, then the user should be rendered with the defined view which is home/account
Here is my code:
routes.js:
'/account': {
controller: 'UserController',
action: 'checkLogin',
view: 'home/account'
}
policies.js:
UserController: {
'*': 'isAuthenticated',
'login': true,
'checkLogin': true
}
It let's me view /account without going through the isAuthenticated policy check for some reason.
There looks to be a little confusion here as to how policies, controllers and views work. As #bredikhin notes above, your controller will never be called because the route is being bound to a view. It's also important to note that policies cannot be bound to views, only to controllers. The correct setup should be something like:
In config/routes.js:
'/account': 'UserController.account'
In config/policies.js:
UserController: {
'*': 'isAuthenticated' // will run on all UserController actions
// or
'account': 'isAuthenticated' // will run just on account action
}
In api/policies/isAuthenticated.js:
module.exports = function(req, res, next) {
// Your auth code here, returning next() if auth passes, otherwise
// res.forbidden(), or throw error, or redirect, etc.
}
In api/controllers/UserController.js:
module.exports = {
account: function(req, res) {
res.view('home/account');
}
}
To put it short: either controller/action-style or view-style routing should be used within the same route in routes.js, not both simultaneously.
According to the router's source code, once there is a view property in a route object, binding stops, so basically Sails never knows to which controller your /account path should be routed, which means that your UserController-specific policy config never fires.
So, just remove the view property from the route, you can always specify the view path (if you want a non-standard one) with explicit rendering from within your action.
For statics work with policies, you can set your route with controller and action:
'GET /login': 'AuthController.index',
And set view/layout in your controller:
index: function (req, res) {
res.view('auth/login', { layout: 'path/layout' } );
},