I need to get this to work:
routes: {
':product' : 'showProduct',
':product/:detail': 'showProductDetail'
showProductDetail never gets called while the ':product' route is set even if it is set afterwards. I tried the following
routes: {
':product(/:detail)': showProductOrDetail
}
But this will not get called when only the second parameter changes.
It is important that I have the product itself or the product and detail in the url.
Does anyone know how to fix this?
There's a little hacky solution to your problem. I have a feeling there is a nicer way to do this but that should work:
routes: {
"product/:id": "showProduct",
"product/:id/details/:did": "showDetails"
},
showProduct: function(id) {
this.showDetails(id);
},
showDetails: function(id, did) {
// Check did for undefined
}
A late response (over a year).. but you can use RegEx in a backbone router to achieve this.
My example presumes the parameters are going to start with a number.
ie: localhost:8888/#root/1param/2param
var router = Backbone.Router.extend({
initialize: function () {
// Use REGEX to get multiple parameters
this.route(/root/, 'page0');
this.route(/root\/(\d+\S+)/, 'page1');
this.route(/root\/(\d+\S+)\/(\d+\S+)/, 'page2');
},
page0:function(){
console.log("no id");
},
page1:function(id1){
console.log(id1);
},
page2:function(id1,id2){
console.log(id1);
console.log(id2);
}
});
Hope this helps.
Related
I'm new to ember and I'm trying to use transitionTo with queryParams but I can't get it to work I tried a lot of the solution but I can't find out what is wrong with my code. here the code for the two routes I'm to transition between:
1- index.js:
export default Ember.Route.extend({
setupController: function(controller, model) {
this._super(controller, model);
controller.set("model", model);
},
model() {
return {
searchQuery: ""
};
},
actions: {
search() {
const query = this.controller.get("model.searchQuery");
this.transitionTo("/search-results", {
queryParams: {
q: query
}
});
}
}
});
2-search-results.js:
export default Ember.Route.extend({
model() {
return {
fieldsInput: []
};
},
setupController: function(controller, model) {
this._super(controller, model);
controller.set("model", model);
}
});
I don't know if anything else should be added. I tried setting queryParams on the controller but it didn't work either. also, I tried adding
queryParams: {
q: ""
},
to the search results route but no use.
When you give url for transitionTo method so you need to provide full URL by constructing including queryParams. This will work
this.transitionTo(`/search-results?q=${query}`);
As you mentioned in comment, you were missing to specify queryParams property in route.
In "search-results.js", you need to access(tell your model) about the param you passed into the file from index.js, so in search-results.js, your model should look a little like this:
model(param) {
return {
fieldsInput: []
};
},
If you look where you've defined "fieldsInput" above, you're going to want to do some sort of Ember-Data lookup (if you are not familiar with it, then watch a youtube video or two, it'll help a lot going forward), to make use of the "queryParam" you passed from index.js.
(Hint: "return this.store.findRecord(someObject, param.someProperty)" is probably what you'll want to use)
Also, if you look in the line just under where you've written "this.transitionTo", you've a typo in your spelling of "queryParams".
Hope this helps.
This works, but I need to use mounted(){} to initiate the function which I think can be avoided but not sure how.
<script>
export default {
data () {
return {
domains: [],
}
},
methods: {
fetchDomains() {
let _this = this;
api._get({url: 'api/domains'})
.then(function (response) {
_this.domains = response.data;
})
}
},
mounted() {
this.fetchDomains()
}
}
</script>
This code doesn't work, but I like to do something like this. Initiating the function in data(){} itself.
<script>
export default {
data () {
return {
domains: this.fetchDomains(),
}
},
methods: {
fetchDomains() {
let data = [];
api._get({url: 'api/domains'})
.then(function (response) {
data = response.data;
})
return data
}
}
}
</script>
Thanks in advance.
Your first code snippet is the correct way to do it.
You can't initialize domains with the data from the API response because it is an async operation which may or may not be resolved successfully at some point in the future, well after the component is mounted. You might also want to do other things like keeping track of the async operation with a loading property which you set to true for the duration of the request.
Your component will initially be in a loading state which does not yet have any domains data, and you need to account for this. Show a loading spinner or something during this time.
I agree with Decade Moon that your first approach is the better way to do it (though you could use created instead of mounted).
The reason your second approach doesn't work is that you return an array and then replace the local variable's value with a different array. What you need to do is populate the array you returned.
new Vue({
el: '#app',
data() {
return {item: this.getItem()}
},
methods: {
getItem() {
let val = [];
setTimeout(() => {
const result = ['first','second','third'];
val.push(...result);
}, 800);
return val;
}
}
});
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.min.js"></script>
<div id="app">{{item}}</div>
I might be deviating slightly from the question (since it explicitly mentions the data property), but I think this might be helpful. Personally, if I want to provide some data with more complex logic I use the computed property. This is great in my opinion and you can read more about it in the docs. The problem in this case is that it doesn't work entirely as expected with asynchronous operations...
However, there is a lovely little module called vue-async-computed which can be found here. It solves this specific problem by providing an asyncComputed property and keeps the code really clean!
I'm trying to build a cart system without the user having to login.
I'm using ironrouter
Router.route('/cart', {
template: 'cart',
data: {
cart: function () {
return Carts.find({uid: Meteor.default_connection._lastSessionId}).fetch();
//return Carts.find({uid: "97gxA35vEAS63qsCR"}).fetch();
}
}
})
In my router I've got a cart method, which returns results based on the current session id... Well thats what Im trying to do anyways :)
It doesn't look like
Meteor.default_connection._lastSessionId
Is returning anything, can't think of a reason why though, it works in a client side file.
My routers are located within /lib/routers.js (typo correction)
If you need anymore information please do let me know, thanks in advanced!
I don't think you need to rely on undocumented features like Meteor.default_connection._lastSessionId for that. You can just use a session variable for that to which you assign a random id if it is not yet set:
Meteor.startup(function() {
if (!Session.get('id')) {
Session.set('id', new Mongo.ObjectID()._str);
}
});
Router.route('/cart', {
template: 'cart',
data: {
cart: function () {
if (Session.get('id')) {
return Carts.find({uid: Session.get('id')}).fetch();
}
}
}
});
Backbone routing allows us to route to different pages.
var Workspace = Backbone.Router.extend({
routes: {
"help": "help", // #help
"search/:query": "search", // #search/kiwis
"search/:query/p:page": "search" // #search/kiwis/p7
},
help: function() {
...
},
search: function(query, page) {
...
}
});
My question is instead of writing different functions for different routes, why not write a single function for all the routes and use a switch statement to determine the exact route and performing tasks based on the route.
It would look something like this.
var Workspace = Backbone.Router.extend({
routes: {
"help": "main", // #help
"search/:query": "main", // #search/kiwis
"search/:query/p:page": "main" // #search/kiwis/p7
},
main: function() {
...
switch(){
case("help") : ...;
case("search") : ...;
}
}
});
I don't know the exact implementation. I just gave a brief idea. Is this possible in Backbone routing?
Because that will lead to a nightmare hell as soon as you have more than 2 o 3 routes/functions, or you need anything more that 2 lines to setup the data and views for each route.
Also, it's much much easier to test your route handlers if you can simply call one function.
If you need one function per your requirements, then what's wrong is your route definition! I assume you are modeling a single page with search functionality and pagination of those search results. Let's suppose that page is accesed with a url like "yourapp/#page":
Enter optional parameters my friend: :)
http://backbonejs.org/#Router-routes
var Workspace = Backbone.Router.extend({
routes: {
"page(/search/:query)(/:page)": "main"
},
main: function(query, page) {
if(query) {
//you're searching
if(page) {
//display specific page
}
else {
//show first results page
}
}
else {
//show you initial views/models
}
}
});
That route will handle: page, page/search/apples and page/search/apples/4
This is my routes object in a BackboneJS app:
routes: {
"" : "_navigate",
"home" : "_navigate",
"blog" : "_navigate",
"photos" : "_navigate",
"notes" : "_navigate",
"about" : "_navigate",
"singlepost_:id" : "_navigate"
},
it redirects routes to the _navigate method, which looks like this:
_navigate: function(postId) {
if (postId) {
// show single entry
return;
}
// show regular entry
},
It works perfectly fine. However, I find the repetitive routes object to be annoying.
My question is: Is there a better way to direct all these routes to the same method without repeating yourself so much?
Thanks!
http://backbonetutorials.com/what-is-a-router/ Check out the section on splats
Any "*splats" or ":params" in route definitions are passed as
arguments (in respective order) to the associated function. A route
defined as "/:route/:action" will pass 2 variables (“route” and
“action”) to the callback function. (If this is confusing please post
a comment and I will try articulate it better) Here are some examples
of using ":params" and "*splats"
routes: {
"/posts/:id": "getPost",
// Example
"/download/*path": "downloadFile",
// Download
"/:route/:action": "loadView",
// Load Route/Action View
},
getPost: function( id ){
alert(id); // 121
},
downloadFile: function( path ){
alert(path); // user/images/hey.gif
},
loadView: function( route, action ){
alert(route + "_" + action); // dashboard_graph
}
Quite simple, really.
routes: {
"*actions:_id": "_navigate"
}
Thanks to Jason Strimpel from the BackboneJS Google Group.