I'm trying to add controller to my Todo list app. Here's the code.
$(function(){
alert(Backbone); // => [object]
alert(Backbone.Controller); // => undefined
TodoList.Controllers.Todos = Backbone.Controller.extend({
routes: {
"documents/:id": "edit",
"": "index",
"new": "newDoc"
},
edit: function(id){
var todo = new Todo({id:id});
todo.fetch({
success:function(model,resp){
new App.Views.Edit({model:todo});
},
error: function(){
new Error({message: "Couldn't find the todo item."});
window.location.hash = '#';
}
});
},
index: function(){
window.App = new TodoList.Views.AppView
}
});
});
As mentioned in the comment, when I alert(Backbone), [object] is returned, while Backbone.Controller returns undefined and I can't figure out why. This is stopping the whole app to work.
It's been replaced with Backbone Router: http://backbonetutorials.com/what-is-a-router/
which backbone version do you have?
Try Backbone.Router instead of Backbone.Controller.
Quote from http://backbonejs.org : as of v5.0
Controller was renamed to Router, for clarity
If that's the case, you can make a reference copy of the Router in order to not alter the existing code :
if(Backbone.Router)
Backbone.controller = Backbone.Router;
Related
How i can edit asset name? its doesnt work. Thanks
let assetService = $injector.get(self.ctx.servicesMap.get('assetService'));
let activeID = self.ctx.data[0].datasource.entityId
let tenantId = self.ctx.dashboard.authUser.tenantId
let asset = {
additionalInfo: null,
createdTime: 1599121131415, // временно
customerId: {
entityType: "CUSTOMER",
id: self.ctx.dashboard.authUser.customerId
},
id: {
entityType: "ASSET",
id: activeID
},
label: null,
name: "kuku", // временно
tenantId: {
entityType: "TENANT",
id: tenantId
},
type: "справочник"
}
assetService.saveAsset(asset)
Thingsboard is built using Angular 10 currently See releases. You correctly injected the Angular service 'assetService'. You need to follow the Angular method of subscribing to the observable from assetService.
Calling
assetService.saveAsset(asset)
without subscribing means nothing happens. From the Angular University Blog
The multiple versions of the Angular HTTP module all have an RxJS Observable-based API. This means that the multiple calls to the HTTP module will all return an observable, that we need to subscribe to one way or the other.
So here's the code to 'subscribe' to the observable described above
assetService.saveAsset(asset).subscribe(
(response) => {
console.log(
"saveAsset call Success:",
response);
},
response => {
console.log(
"saveAsset call Error:",
response);
},
() => {
console.log(
"saveAsset observable Complete"
);
});
Let me know if there's a mistake in the code above, I didn't test it. And thanks for your question Anzor - it led me to a solution to make a custom Thingsboard widget along with the Widgets Development Guide.
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
}
I'm using the following router in my app:
app.Router = Backbone.Router.extend({
// define the route and function maps for this router
routes : {
"" : "showLogin",
// Sample usage: http://ServerManager/
"login" : "login",
// Sample usage: http://ServerManager/#login
"logout" : "logout",
// Sample usage: http://ServerManager/#logout
"folders" : "listFolders",
// Sample usage: http://ServerManager/#folders
"folders/:name" : "showFolder",
// Sample usage: http://ServerManager/#folders/System
"*other" : "defaultRoute"
// Sample usage: http://ServerManager/#badHash
},
showLogin : function() {
console.log("Home page loaded. Redirecting to #login page.");
this.navigate("login", {trigger: true, replace: true});
},
login : function() {
//console.log("login route fired");
// delete sessionStorage items and load a new loginview
this.changePage(new app.LoginView());
},
logout : function() {
//console.log("logout route fired");
// Clear the token and other session items from sessionStorage
sessionStorage.clear();
this.navigate("login", {trigger: true, replace: true});
},
listFolders : function() {
//console.log("listFolders route fired.")
if (app.folderView === undefined) {
console.log("creating new app.folderView");
app.folderView = new app.FolderView();
}
else {
console.log("using existing app.folderView");
}
this.changePage(app.folderView);
},
showFolder : function(name) {
console.log( app.router.routes[Backbone.history.fragment] );
//console.log("showFolder route fired.")
this.changePage(new app.ServiceView({folder : name}));
console.log( app.router.routes[Backbone.history.fragment] );
//app.router.navigate("folder/" + name, {trigger: false});
},
defaultRoute : function() {
alert("Error. Page doesn\'t exist.");
},
changePage : function(page) {
$(page.el).attr("data-role", "page");
page.render();
$("body").append($(page.el));
var transition = $.mobile.defaultPageTransition;
$.mobile.changePage($(page.el), {changeHash : true, transition : transition});
}
});
If I use
app.router.navigate("folders", {trigger: true, replace: true});
it successfully sends the app to server/#folders, but when I pass
app.router.navigate("folders/" + id, {trigger: true, replace: true});
it triggers the root of the app and loads my login page. I can see the correct URL (e.g. server/folders/folder1) temporarily flash before the redirect happens. Any ideas as to what's happening here?
Backbone routers expect more generic routes last.
Set-up the folders/:id route followed by the folders route.
UPDATE
Actually, after thinking about it, this may not be the case. Can you post console output? Is it calling the correct function?
Perhaps the $.mobile ... changeHash: true is conflicting. You should probably only have one of the frameworks change the url hash for you.
If I loop the collection in the view, it's seems empty, alert dialog don't show up. When I use console.log(this.collection) in this view, it's look ok (16 element in this collection).
My router: (collection url: '/api/employees', this is a rails json output)
Office.Routers.Employees = Backbone.Router.extend({
routes: {
"": "index"
},
initialize: function() {
this.collection = new Office.Collections.Employees();
this.collection.fetch();
},
index: function() {
var view = new Office.Views.EmployeesIndex({ collection: this.collection });
view.render();
}
});
and my index.js view:
Office.Views.EmployeesIndex = Backbone.View.extend({
render: function() {
this.collection.each( function( obj ){ alert(obj); } );
}
});
Edit:
This is the output of the console.log(this.collection) in view : http://i.stack.imgur.com/ZQBUD.png
Edit2:
I thing Rails is the guilty. When I work whit static collection, everything works fine
var collection = new Backbone.Collection([
{name: "Tim", age: 5},
{name: "Ida", age: 26},
{name: "Rob", age: 55}
]);
collection.fetch() makes an asynchronous request to the server. The index callback doesn't wait for the fetch to return. So your render function is rendering an empty collection.
You need to use the success callback of the fetch method:
index: function() {
this.collection.fetch({
success: function(data) {
var view = new Office.Views.EmployeesIndex({ collection: data });
view.render();
}
});
}
Note that the Backbone documentation recommends bootstrapping any initial data you need by including the data in the document itself:
When your app first loads, it's common to have a set of initial models
that you know you're going to need, in order to render the page.
Instead of firing an extra AJAX request to fetch them, a nicer pattern
is to have their data already bootstrapped into the page.
The fetch has probably not completed by the time your view renders. Try the following:
index: function() {
var p, collection, view;
collection = new Office.Collections.Employees();
p = collection.fetch();
view = new Office.Views.EmployeesIndex({ collection: collection });
p.done(view.render);
}
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.