Backbonejs conditional route for wizard - javascript

I'm trying to create a little wizard with backbonejs in which the answers to certain questions determine the path being taken through the wizard. Is there a way in backbonejs to assess the current state of the model and navigate to the next page accordingly? Or is there another way of accomplishing this best in a backbonejs kind of way?

I think the best way is to treat each answer as a different route. That way when the user selects an answer, the route is change and you can load/change views accordingly in your router. Be sure to make use of variables in routes like
routes: {
":question/:answer": "checkAnswer"
}
Where question and answer are variables
Hope this helps

You can have your router subscribe to the model's "change" or "change:[attribute]" event, then change the route and page accordingly
OR whenever you want to go to a new page call the router's navigate function
router.navigate("question1/option1", {trigger: true});
This will change the url and also trigger the route you set up for "question1/option1"
So if your router is:
router = Backbone.Router.extend({
routes: {
"question1/option1": "answer1"
},
answer1: function() {
//change the page / or take whatever other action you want.
}
answer1 function will be called to setup your next page.

Related

Ember.js Wildcard URL

Any ember-way ideas to make a manual transition to a wildcard route with a dynamic segment at the end */:category_name, so I can manually build a "breadcrumbish url version" example, suppose a user enters to /banana I need to transition the user to /Groceries/Healthy/Fruit/Banana.... groceries, healthy, fruit might be entered as well so /Fruit would be transitioned to /Groceries/Healthy/Fruit... I was able to make it work using window.history.replaceState on the model hook of the route but strange enough it only works if it's being refreshed or type in by user, not while transitioning in template, thanks in advance guys
Route as is
this.route('products', function(){
this.route('wildcard_handler', {path: '*/:category_name'});
this.route('handler', {path: '/:category_name'})
});
Recap of cases:
Case 1:
User enters /products/banana
-Redirect to /products/groceries/healthy/fruit/banana
User enters /products/fruit
-Redirect to /products/groceries/healthy/fruit
Case 2:
User enters /products/groceries
-All good, it's correct.
Case 3
User enters /products/groceries/snacks
-doesn't exists so, 404 redirects.
All of this trouble is only for making a better UX for a new ecommerce I'm building, the normal suggested way is to just use one dynamic segment
Like
this.route('products', function(){
this.route('handler', {path: '/:category_name'})
});
It's fair, but it's way nicer to build the breadcrumbish url
Again, thanks in advance
Case 1:
If you want to redirect the user to another route before resolving the model, you can use beforeModel() hook. You can also use redirect() hook to redirect the user to another route. For example (when user visits /products/fruit, you can redirect them to products/groceries/healthy/fruit in redirect hook),
redirect(model, transition) {
this._super(...arguments);
this.transitionTo('products.groceries.healthy.fruit');
}
Refer this link to know about the predefined hooks in routes.
Case 3:
Refer this link to know about wildcarding routes in your application.

Ember.js - Setting a model and routing dynamically via API data

So I'm working on building a dynamic model for a project that reacts to data sent from an API. The api will return, among other things, what your location should be and this in turn becomes the url. So, eg:
{
location: 'xyz'
(...)
}
So currently my router will transition to the right route dynamically. But I still have to hardcode each route ( IndexRoute, LocationXYZRoute, LocationABCRoute, etc).
My goal is to create a single route that handles things dynamically. We'll call it App.LocationRoute and my routes would look something like:
App.Router.map(function() {
this.resource(':location', function() {
this.route(':subLocation')
}
}
Now, I have two architectural questions:
1) Whats a good way to handle this sort of dynamic routing? (I've read through the guide about dynamic routing using the ':post_id' type example, but I think I need a more holistic example to really grasp it.
2) The API sends back a whole host of other data as well. I want to add this to the route's model but I also have some other static models. Doing...
this.controllerFor(location).set('content', APIdata);
... works, but it does not set for routes currently using static models. I tried something like:
this.controllerFor(location).set('apiData', APIdata);
and...
this.controllerFor(location).set('model:apiData', APIdata);
... but neither worked.
Any suggestions?
1) Yes, you should use dynamic segment
this.resource('location', { path: '/location/:location_id' }, function() {
this.resource('sublocation', { path: '/sublocation/:location_id' });
});
2) Are you using ember-data? You could check sideloaded data. Anyway, you could read the json and set the payload of each entity for each specific route.
this.controllerFor('location').set('content', APIdata.location);
this.controllerFor('user').set('content', APIdata.user);
People could help you better, if you separate your questions and create a http://emberjs.jsbin.com/ with isolated each specific case?

How can I reuse/dry these routes in ember.js

I have these routes
this.resource('politicians');
this.resource('politician', { path: '/politicians/:politician_id', function () {
// Non nested interface so non nested politician route.
this.resource('questions', function () {
this.resource('question', { path: ':question_id' });
});
});
this.resource('questions', function () {
this.resource('question', { path: ':question_id' });
});
I'd like the question route to be rendered anywhere (using a modal) in the app without losing the current context, but still have a specific/unique url for each question, knowing that the question you got from the nested questions route and the non nested ones are the same.
this.resource('question', { path: ':question_id' });
The thing is that I don't want to make a custom outlet for that because then I won't have a url for each question.
This sort of problem is best solved by using query-params and hooking up the modal based on params. If you don't want to do that you're really stuck with building questions into each route if you want it to be URL based.
Here's an example: http://emberjs.jsbin.com/ucanam/3566/edit
What you're looking for is Ember's {{render}} helper. Simply place a {{render 'question' questionModel}} inside the modal you wish to use.
You can learn about the render helper here
EDIT:
Here is a jsbin to show the basic idea of how to use a render tag in this way. This jsbin renders the same template in 2 different ways; Once tied to a route url and once by using the render helper.
jsbin here

Backbone Collection get(id) method

I have one main home page in my application and another page for each post that can be accessed through a list displayed in the home page..
this is how my router looks like :
var AppRouter = Backbone.Router.extend({
initialize: function(){
this.model = new model();
this.collection = new collection();
},
routes: {
"" : "showForm",
"post/:id" : "showPost"
},
showPost: function(id){
var curmodel = this.collection.get(id);
var post = new postView({model:curmodel});
post.render();
$(".maincontainer").html(post.el);
},
showForm : function(){
var qcView = new qcV({model:this.model, collection:this.collection});
qcView.render()
$(".maincontainer").html(qcView.el);
}
});
this is what one of the links to the posts in this list looks like
<h2><a id= "<%=_id%>" href="#post/<%=_id%>"><%=name%></h2></a>
my first question is: Is it dangerous to link pages with a hash-based URL in this manner?
my second question is: I am having no problem navigating to a posts view if I click one of the links in my home page. I my url successfully changes to something like http://127.0.0.1:3000/#post/51ffdb93c29eb6cc17000034 and that specific post's view is rendered. However at that point if I refresh the page, or if I directly type http://127.0.0.1:3000/#post/51ffdb93c29eb6cc17000034to my URL bar the this.collection.get(id) method in my showPost method in the router returns undefined. Can anyone help me figure out why this is the case?
I checked couple times that my initialize method gets called both times, and my collection and model is created successfully
For #2, you are most likely not fetching the collection on the "post" route. Try fetching the collection (if it does not exist) and then call render. That should do the trick!
I think #Trunal's on the right path for the 2nd question. For the first, no, it's not "dangerous". You're not really doing anything different than you would with a classic server-side app, passing information to the server via GET to retrieve info. In my opinion, this should be the preferred approach to implementing routes (rather than attempting to trigger backbone.history.navigate manually, as it avoids all kinds of setup and eventing issues that might otherwise occur).

Parameter at beginning of route in durandal

The typical route in Durandal looks like:
Regular - http://mysite.com/#/Home
Id - http://mysite.com/#/Person/123 (Person/:id)
I'm trying to figure out which method(s) I need on http://durandaljs.com/documentation/Router/ I need to overwrite to support something like this:
http://mysite.com/#/Abc123/Home (:siteId/Home)
http://mysite.com/#/Abc123/Person/123 (:siteId/Person/:id)
How would I implement something like this?
You answered your own question. To implement http://mysite.com/#/abc123/Home you have to define a route that models that, for example:
var router = require('durandal/plugins/router');
router.mapRoute('#/:sideId/home','viewmodels/customViewModel','This is the title of the view');
when someone goes to your route, it will navigate to your customViewModel.
Just remember, that the router will navigate to the easiest route first, so order them correctly (for example, if you have router.mapRoute('','viewmodels/home','home view') as your first route, the router will always go to this route, and not read look further in its router queue).

Categories