This is how I do my routes in backbonejs where the routing and its params are obtained first before deciding which external template to call. I find this is quite flexible.
var Router = Backbone.Router.extend({
routes: {
//'': 'renderBasic',
':module/:method/': 'renderDynamicViewPageBasic',
':module/:branch/:method/': 'renderDynamicViewPageBranch',
':module/:branch/:method/set:setnumber/page:pagenumber/': 'renderDynamicViewPagePager',
':module/:branch/:method?set=:setnumber&page=:pagenumber': 'renderDynamicViewPagePager'
},
renderDynamicViewPageBasic: function (module,method) {
$(el).html(Handlebars.getTemplate('template1')(data));
},
renderDynamicViewPageBranch: function (module,branch,method) {
$(el).html(Handlebars.getTemplate('template2')(data));
},
renderDynamicViewPagePager: function (module,branch,method,setnumber,pagenumber) {
$(el).html(Handlebars.getTemplate('template3')(data));
}
});
How about in emberjs, can I do the same - do the rout and get its params afirst before deciding which external template to call?
I read the documentation and tested it. It seems to be less flexible - for instance,
App.Router.map(function() {
this.route("about", { path: "/about" });
this.route("favorites", { path: "/favs" });
});
Is it possible to get the route and params and then the controller before getting the template?
if not, it seems to be the same as case using Angularjs which I finally decided not to use it because it gets the template first before sorting out the params.
You can define the template "post params" in EmberJs using the renderTemplate hook, where you can customize which template you'd like to use.
http://emberjs.jsbin.com/oXUqUJAh/1/edit
App.Router.map(function() {
this.route('apple', {path: 'apple/:id'});
});
App.AppleRoute = Ember.Route.extend({
model: function(params) {
return {coolProperty: params.id};
},
renderTemplate: function(controller, model) {
// send in the template name
this.render(model.coolProperty);
}
});
You can pass a function together with $route params to get customized result in angularjs actually.
template: function($params) {
return app.$templateCache.get($params); // or make template yourself from another source
}
Related
I'm working on a project that uses Rails and React, with react-router version 4.2.0 and react-router-redux 5.0.0-alpha.9. It's the first time I use React and I'm having trouble routing.
In my routes.jsx file I have the following path:
const routes = [
{ path: /\/events\/(\d)$/, action: () => <EventForm /> },
];
When I type http://localhost:3000/events/2 in my browser I get the content back.
I want to modify my route so this link won't be valid unless there's a userToken appended to it as a query string. (I know this is not the best security practice but it's valid for the purpose of this project)
For example, the following link http://localhost:3000/events/2 should not work, but the link http://localhost:3000/events/2?userToken=abc should work.
I tried these options but it didn't work:
{ path: /\/events\/(\d)\?userToken\=(\w)$/, action: () => <EventForm /> }
{ path: /\/events\/(\d)\?userToken=[\w]$/, action: () => <EventForm /> }
Thanks!
One way is to check url param in componentDidMount lifecycle method of EventForm:
class EventForm extends Component{
componentDidMount(){
const {location, history} = this.props // these are by design in props when using react-router
if(!location.query.userToken){
history.push('/login') // or whatever route
}
}
render(){
return (<div>...</div>)
}
}
export default EventForm
So I have a Rails API and an Ember application. At the moment, my Ember has a login.hbs template and a login.js controller.
I have done a ember install ember-ajax (https://github.com/ember-cli/ember-ajax).
On entering an email and password, I click on the login button which calls my login.js action loginClicked()
I have the following in my login controller:
// login.js controller
import Ember from 'ember';
export default Ember.Controller.extend({
email: '',
password: '',
actions: {
loginClicked() {
// alert("email: " + this.get('email') + "\npassword: " + this.get('password'));
let params = {
email: this.get('email'),
password: this.get('password')
};
post('/authenticate', {
params: params
});
}
}
});
In my login.js route handler, I have injected the ember-ajax service:
// login.js route handler
import Ember from 'ember';
export default Ember.Route.extend({
ajax: Ember.inject.service()
});
The problem is, my Mac terminal console is outputting an error saying:
controllers/login.js: line 16, col 7, 'post' is not defined.
I have also tried injecting the ember-ajax service into my controller but it made no difference.
Am I doing something wrong ?
Everything is described into the ember-ajax github page https://github.com/ember-cli/ember-ajax
export default Ember.Controller.extend({
ajax: Ember.inject.service(),
actions: {
loginClicked() {
let params = {
email: this.get('email'),
password: this.get('password')
};
return this.get('ajax').request('/authenticate', {
method: 'POST',
data: params
});
}
}
});
Basically, to access any property of your controller (component, ...) in ember, you need to get it using this.get('propertyName').
Here you need to use the request method of the ajax property (the injected service).
I have a page with a button that will change the state of the resource on the server. Everything is wired up and working fine. But I had to resort to a server response that sent the browser "back" because I don't want to display a new template for the action url.
This seems like a typical thing to do: ask the server to do something, then get the current state of the resource and redisplay it in the current template without refetching the template.
The markup on the page is like this:
<a ng-href="/api/preference/{{video._id}}/add_to_watchlist" data-method="get">
<i rel="tooltip" data-original-title="Add to watchlist" class="icon-3x action-icon
icon-plus-sign" ng-class="{iconSelected : video.user_watchlist == 1}">
</i>
</a>
This highlights the icon depending on the value of $scope.video.watchlist. When clicked it fires a custom action on the server to add the video being viewed to the current user's watchlist. The url created is /api/preference/{{video._id}}/add_to_watchlist, this fires the server controller, which does the right thing but instead of going to a template for /api/preference/{{video._id}}/add_to_watchlist the server responds by telling the client to go "back" in Rails this is redirect_to :back.
Clearly this is wrong. It works but refetches the entire page markup and data.
The AngularJS controller that loads the original data is here:
GuideControllers.controller('VideoDetailCtrl', ['$scope', 'Video',
function($scope, Video) {
var pattern = new RegExp( ".*/([0-9,a-f]*)", "gi" );
//ugh, there must be a better way to get the id!
$scope.video = Video.get({ id: pattern.exec( document.URL )[1] });
}
]);
Here is the resource that gets the json
var VideoServices = angular.module('VideoServices', ['ngResource']);
VideoServices.factory('Video', ['$resource',
function($resource){
return $resource("/api/videos/:id", {id: "#id"}, {
update: {method: "PUT"},
query: {
isArray: true,
method: "GET",
headers: {
"Accept": "application/json",
"X-Requested-With": "XMLHttpRequest"
}
},
get: {
isArray: false,
method: "GET",
headers: {
"Accept": "application/json",
"X-Requested-With": "XMLHttpRequest"
}
}
});
}
]);
Somehow I need to
tell the server to add_to_watchlist without changing the browser URL
trigger a refetch of the video json without reloading the template.
It seems like you're relying on routing to handle a model update on the server, instead of doing it through angular's $resource service. Here's a quick and dirty:
Instead of routing, call a function when the user clicks:
<a ng-click="addToWatchlist(video._id)">
<i rel="tooltip" data-original-title="Add to watchlist" class="icon-3x action-icon
icon-plus-sign" ng-class="{iconSelected : video.user_watchlist == 1}">
</i>
</a>
Add the click handler function to your controller (I'm using $http here, but you would be better off adding a custom action to your Video resource). On the success callback you can reload the video. Or, better yet, you can return the video from the add_to_watchlist action.
Check out http://docs.angularjs.org/tutorial/step_07 which explains the $routeParams (to answer your comment about getting the video id).
GuideControllers.controller('VideoDetailCtrl', ['$scope', '$http', '$routeParams', 'Video',
function($scope, $http, $routeParams, Video) {
$scope.video = Video.get({ id: $routeParams.videoId });
$scope.addToWatchlist = function(videoId) {
$http.get('/api/preference/'+videoId+'/add_to_watchlist').success(function() {
$scope.video = Video.get({ id: $routeParams.videoId });
};
};
}
]);
I'm using devise, rails with backbone. All my backbone routes are working just fine. But non-backbone routes like /accounts/login that are supposed to rendered by rails are being globbed with backbone router.
SS.Routers.ApplicationRouter = Backbone.Router.extend({
initialize: function() {
this.el = $("#content");
},
routes: {
"": "home"
},
"home": function () {
console.debug("Got home request");
var view = new SS.Views.Home();
this.el.empty().append(view.render());
}
});
The actual request/response to the /accounts/login is happening from rails logs. But Backbone home root gets triggered afterwards and my home page is rendered.
My layout has
$(function () {
SS.init();
});
from
window.SS = {
Models: {},
Collections: {},
Views: {Providers: {}},
Routers: {},
init: function (data) {
console.debug("Initializing Backbone Components");
new SS.Routers.ApplicationRouter();
new SS.Routers.ProvidersRouter();
if (!Backbone.history.started) {
Backbone.history.start();
Backbone.history.started = true;
};
}
};
Which is triggering my home route again.
"" route in backbone is not supposed to be globbing /accounts/login but it is.
A little bit of debugging is showing me that /accounts/login is being gobbled by "" since the fragment is an empty string.
And the fragment is an empty string in the all the cases where there is no match for backbone routes.
Code from backbone 0.9.2
loadUrl: function(fragmentOverride) {
var fragment = this.fragment = this.getFragment(fragmentOverride);
var matched = _.any(this.handlers, function(handler) {
if (handler.route.test(fragment)) {
console.debug(handler);
console.debug(fragment);
handler.callback(fragment);
return true;
}
});
return matched;
},
Any suggestions?
Add a class ('passThrough') or 'data-passThrough=true' attribute to the link. Catch this class/attribute in your router and return true so Backbone stops handling it and the browser treats it as a regular link.
public ActionResult DoSomething(string[] arr, bool someBool, int someInt) { }
trying to call the above method from jQuery:
var test = [];
test.push('dog');
test.push('cat');
$container.load('MyController/DoSomething',
{ 'arr[]': test, 'someBool': true, 'someInt': 1 },
function(response, status, xhr) {
// ...
});
the array paramater is null, other params are fine. What am I doing wrong?
Chrome developer tools shows form data being submitted as
arr%5B%5D%5B%5D:dog
arr%5B%5D%5B%5D:cat
someBool:true
someInt:1
not sure whats going on there but doesn't look right to me
If you are using jquery 1.4 you might need to set the traditional parameter to true in order to be compatible with the default model binder format in ASP.NET MVC:
var test = [];
test.push('dog');
test.push('cat');
$.ajax({
url: 'MyController/DoSomething',
type: 'GET',
traditional: true,
data: { arr: test, someBool: true, someInt: 1 },
success: function(result) {
$container.html(result);
}
});
or if you prefer the .load() method:
var data = { arr: test, someBool: true, someInt: 1 };
$container.load('MyController/DoSomething', $.param(data, true),
function(response, status, xhr) {
// ...
});
Just remove []
{ 'arr': test, 'someBool': true, 'someInt': 1 },
Posted values (checking with Firebug).
arr[] dog
arr[] cat
someBool true
someInt 1
Example on jsFiddle
can you see if this problem is similar to yours:
Passing an nested arrays to asp.net mvc using jQuery's $.ajax
Even i was facing error, in passing array from HTML page to aspx page.
my requirement was to load the aspx page in a DIV tag of the html page. on the page load i need to pass these JS array values to aspx page load.
i used below method.
$('#<divTagID>').load("Targetpage.aspx",{"Arr":JSArrValues});
In aspx page load event i can access this values as:
string results = Response["Arr[]"];
Thanks to JQuery API documentation enter link description here and stackoverflow