I want to use the current route's name in a v-if statement in a a template. I have read that there is a complicated 3rd party way, but I want something better.
<template v-if="$this.routes.getName() == '/customers'">
if you register the route with a name then it's too simple
Your route
{
name: 'Foo',
path: '/foo'
component: 'Foo.vue'
}
Then it's just
this.$route.name
And it will return Foo
You can compare with name, however if you want to compare with path then
this.$route.path // it will return exact path after domain i.e. www.google.com/foo
if(this.$route.path === '/foo') {
console.log('I am on foo route')
}
Try loggin your route object and explore what else you have
console.log(this.$route)
Related
I've implement a redux effect takeLeading that will ignore subsequent actions if the saga is currently running:
export const takeLeading = (patternOrChannel, saga, ...args) => fork(function*() {
while (true) {
const action = yield take(patternOrChannel);
yield call(saga, ...args.concat(action));
}
});
I use this for API fetching in my application, where each endpoint in my API has its own action type. So for GET methods it's useful to block if the request has already been dispatched somewhere else in the app. The saga looks like:
return function* () {
yield all([takeLeading(GET_USER_ID, callApiGen), takeLeading(GET_WIDGET_ID, callApiGen)]);
}
The obvious problem is that if I want to get two different user IDs, the second will block because it too has action type GET_USER_ID. Short of making a different action for each possible parameter, is there a way to implement some takeLeadingForFunc(<action>, (action) => <id>, saga) that allows me to keep the concise format of specifying one effect per request type but allows me to not block if the <id> is different? I was trying to wrap takeLeading with takeEvery to implement something but couldn't quite get it.
EDIT:
I got something like this to work:
export const takeLeadingForFunc = (f) => (patternOrChannel, saga, ...args) => fork(function*() {
let takeLeadings = {};
while (true) {
const action = yield take(patternOrChannel);
if (!(f(action) in takeLeadings)) {
yield call(saga, ...args.concat(action))
takeLeadings[f(action)] = yield takeLeading((ac) => f(ac) === f(action) && ac.type === action.type, saga, ...args)
}
}
});
Which takes an extractor function f that should return a primitive. This feels kind of hacky, so was wondering if there's a more idiomatic way to do this.
const router = new VueRouter({
routes: [
{path: '*', redirect: '/'}
}
)}
I have set this as redirect route in routes.js file.
how i can set more than 1 redirect path and call it on particular condition
In the component you want to set multiple redirects based on a condition you can use beforeRouteEnter() property in that component like below:
beforeRouteEnter(to,from,next){
next(vm => {
if(condition 1){
vm.$router.push('the path you want to redirect');
}else if(condition 2){
vm.$router.push('the path you want to redirect');
}else{
//no redirect
next();
}
});
}
Since the vue instance is not yet created when beforeRouteEnter() property is called you cannot use this to access the vue instance and follow the process the method shown above via vm
Another way would be by using route meta feilds where you would include a meta field when defining a route and checking for a meta field in the global navigation guard. In that global navigation guard you can redirect by checking various if statements.
Here is a screenshot from their docs about <Link> component
What state do they mean? A Redux state?
How does it look like to pass a state? Like this?
pathname: '/foo',
query: {
x: this.props.x,
},
state: store.getState()
It's a piece of information that you'd like to send to the next page. Nothing to do with Redux. It's a plain object. I believe Flipkart is a very nice example of how it can be used to improve user experience:
Go to a Flipkart search page on a mobile device (or simulate one using Chrome DevTools)
Tap on one of the items
You'll see that the transition happens instantly and pieces of information like product images, title, rating and price are readily available on the product page. One way to implement that is passing the state they had already loaded on the search page onto the next one:
<Link
to={`/product/${id}`}
state={{
product,
}}
/>
And then:
function ProductPage(props) {
// Always check because state is empty on first visit
if (props.location.state.product) {
console.log(props.location.state.product);
// { id: '...', images: [...], price: { ... } }
}
}
There are two ways to pass data from one route to another via Link.
URL Parameter.
As state.
URL parameter help when the route params contain strings for example we want to route to a particular profile:
<Link to='/azheraleem'>Visit Profile</Link>
However, the later i.e. the state helps us pass data from one route to another which is complex data structure. (objects/arrays).
As per the react router documentation, in case of passing data from one route to another it can be done as per the below code sample:
<Link
to={{
pathname: "/profile",
search: "?name=azheraleem",
state: { fromDashboard: true }
}}
/>
The pathname is the link to the route while the search attribute contains the query string parameters, thus the on clicking the link the URL will form something like:
http://localhost:3000/profile?name=azheraleem.
But the state variable value can be accessed in the called route using the useLocation hook:
import { useLocation } from "react-router";
const profile() => {
let data = useLocation();
console.log(data.state.fromDashboard);
}
The the state property of the to prop is the param of pushState method of History DOM object described here
That props used in push/replace methods of router as described here for transitions to a new URL, adding a new entry in the browser history like this:
router.push('/users/12')
// or with a location descriptor object
router.push({
pathname: '/users/12',
query: { modal: true },
state: { fromDashboard: true }
})
It also mentioned here:
router.push(path)
router.push({ pathname, query, state }) // new "location descriptor"
router.replace(path)
router.replace({ pathname, query, state }) // new "location descriptor"
state is a property that's part of the object you can provide to the to prop of the <Link> component.
It is particularly useful if you want to send data from the current view to one the <Link> directs you to, without using common techniques such as setting URL parameters or using libraries, such as Redux.
There isn't much official information about the state key, but here's what I found in the source code of that component:
Links may pass along location state and/or query string parameters
in the state/query props, respectively.
So basically, it's like sending props to a component from a parent. Here, you are sending "state" from the current view to the target view. That's about it, really.
In simple term state in <Link/> component is use to pass information from one view to other view through router in form of object.On other page it can be access using prop.location.state.
(Note: on browser refresh state no longer contain information)
To pass state in Link:
<Link to={{pathname: "/second_page", state: {id: 123}}} />
To access id in second page view:
let id = props.location.state.id;
For more Link properties : React Router Link
I have an Ember app consuming a rails based webservice.
On the Rails side, I have some enums, they are simply arrays.
Now, I would like to retreive those enums in the Ember app, and render them for select values.
The webservice returns a JSON response :
get '/grades.json'
{"grades":["cp","ce1","ce2","cm1","cm2"]}
On the Ember side, I created a GradesRoute like this :
App.GradesRoute = Ember.Route.extend({
model: function () {
return Em.$.getJSON('api/v1/grades.json')
}
}));
Then, I think I need it in the controllers where these enums are in use:
App.StudentsController = Ember.ArrayController.extend({
needs: ['grades'],
grades: Ember.computed.alias('controllers.grades')
}
));
So at least I thought I could iterate over the grades in the students template.
{{#each grade in grades}}
{{grade}}
{{/each}}
But I get no output at all... debugging from the template and trying templateContext.get('grades').get('model') returns an empty array []
Any idea on how I could load and access this data ?
So I ended up with ApplicationRoute, which is the immediate parent of StudentsRoute, so needs is relevant in this case.
App.ApplicationRoute = Ember.Route.extend({
setupController: function(controller) {
Em.$.getJSON('api/v1/enums.json').then(function(data){
controller.set('grades', data['grades']);
controller.set('states', data['states']);
}
}
});
Now I can create an alias for each enums I need to use accross my app.
App.StudentsController = Ember.ArrayController.extend({
needs: ['application'],
grades: Ember.computed.alias('controllers.application.grades'),
states: Ember.computed.alias('controllers.application.states')
});
I'm still not confident enough to be sure this is the way to go, any suggestion is welcome !
You just have some of your paths mixed up. In StudentsController, controllers.grades refers to the actual controller, not it's model. The following code should clear things up as it's a bit more explicit in naming.
App.StudentsController = Ember.ArrayController.extend({
needs: ['grades'],
gradesController: Ember.computed.alias('controllers.grades'),
grades: Ember.computed.alias('gradesController.model.grades')
});
Also, be aware that using needs only works if your grades route is a direct parent of your students route. If it's not a direct parent, you won't get back the data you want.
The problem
I'm trying to filter json data and display only a portion of it on an Angular page, based on the page's current URL.
In detail
I have a list of 100 JSON objects, and each one looks like this:
{
"name": "Evangeline Perreault",
"age_1": 1,
"total_age": 1,
"photo_small": "img/400/001_400.jpg",
"photo_medium": "img/800/001_800.jpg",
"photo_large": "img/1200/001_1200.jpg",
"photo_extralarge": "img/1600/001_1600.jpg",
"video": 67443664,
"id": 1,
"quote": "test quote here and here",
"type": 1
},
The 'type' attribute is what I want to use to filter out the subsets of my data. With that in mind, I tried to setup my URL structure to tie the type attribute here to my url. Here is my route:
angular.module('100_Ages', ['mydirectives', 'ngResponsiveImages']).
config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/100_Ages/nav/:personType', {templateUrl: 'partials/person-list.html', controller: NavListCtrl}).
otherwise({redirectTo: '/100_Ages'});
}]);
So, I have pointed the route to the 'type' field in my JSON and I tried writing a controller to tie the two together.
function NavListCtrl($scope, $routeParams, $http) {
$http.get('person.json').success(function(data) {
angular.forEach(data, function(person) {
if (person.type == $routeParams.personType)
$scope.person = person;
});
});
}
And here is my partial template:
<div class="nav_outer"><img class="nav_img" ng-src="{{person.photo_small}}" ng-alt="{{person.name}}" /></div>
I expected this to display all the matching images for the URL type I'm on. So, if I'm on "/100_Ages/nav/3", I expected all the images (roughly 10 pictures) from the objects with a type of "3" to display. However, it only displayed the last object with a type of "3".
So, I tried an ng-repeat like so:
<div class="nav_outer" ng-repeat="person in persons"><img class="nav_img" ng-src="{{person.photo_small}}" ng-alt="{{person.name}}" /></div>
I expected that to loop through and show all the matching images, but that made nothing at all show up.
I think my problem has to do with the angular.forEach, but I'm not sure how else to tie my JSON type to the page's typeid.
Thanks for any suggestions.
The ng-repeat should work if you push each item into an array. (Also, you are referring to a 'persons' object in the ng-repeat, which doesn't exist according to code provided). So, try this:
$http.get('person.json').success(function(data) {
$scope.persons = [];
angular.forEach(data, function(person) {
if (person.type == $routeParams.personType)
$scope.persons.push(person);
// or alternatively - this.push(person), with the optional 3rd param of $scope.persons (I don't really understand that, but whatever...)
});
});
Now with the array populated, your ng-repeat="person in persons" should work.
UPDATE:
If the success object was already an array of objects, then just set the scope object to the array - no need to iterate through them:
$http.get('person.json').success(function(data) {
$scope.persons = data;
})