I have Backbone view. It load content (component on backbone with AJAX):
render: function () {
var self = this;
$.get('/Blog', request, function (data) {
self.$el.html(data);
model.trigger('blogContainerLoaded');
});
}
Component code:
window.App = {
init: function (options) {
var BlogModel = Backbone.Model.extend({
});
var model = new BlogModel();
var BlogController = Backbone.Router.extend({
routes: {
"": "posts",
"posts": "posts",
"posts/:postId": "post",
"posts/:postId/": "post",
},
posts: function (anchor) {
window.App.views.posts.render(anchor);
},
post: function (postId, commentId) {
window.App.views.post.render(postId, commentId);
},
});
var controller = new BlogController();
if (notLoaded) {
var views = {
posts: new PostListView({ model: model, controller: controller }),
post: new PostView({ model: model, controller: controller }),
};
this.views = views;
Backbone.history.start();
}
}
};
var PostListView = Backbone.View.extend({
el: $(".posts"),
events: {
"click .js-edit-message": "editMessage",
"click .js-open-post": "navigateToPost",
"click .js-move-post": "move"
},
editMessage: function () {
debugger;
},
navigateToPost: function () {
debugger;
},
move: function () {
debugger;
},
All html code loads with ajax.
It works, but events (clicks and other) not firing!
When I load Blog component without AJAX - events working. Please Help!
Most likely your view is instantiated before your ajax call is complete. Because ajax is asynchronous, while it does load (eventually) your code to initialize the view runs first. Thus, when your view is looking to attach the events to your DOM, the necessary elements are not present.
This would also explain why when you eliminate the ajax portion of it, the code works (it's now synchronous and the DOM is present before you initialize your view code.)
Try putting your initialization code inside the ajax callback like this: (if possible)
render: function () {
var self = this;
$.get('/Blog', request, function (data) {
self.$el.html(data);
self.blogContainer = new BlogContainerView(); // Or however you do it
});
}
Another possibility is to keep your trigger.('blogContentLoaded') then attach the events at that time. Backbone.View's delegateEvents() method might be useful in your case.
Or something of that nature. Now you're guaranteed that the DOM is available for your View object to attach events to.
Related
my code of module is.
spine.module('communityApp', {
startWithParent: false,
define: function (communityApp, App, Backbone, Marionette, $, _) {
console.log("communityApp.js");
// Setup the router for this module
var Router = Marionette.AppRouter.extend({
before: function () {
console.log("communityApp.js: router.before()")
App.startSubApp("communityApp", {});
},
appRoutes: {
"community": "showCommunityTab",
"community/pforum": "getPforum",
"community/questions":"getQuestions",
"community/events": "getEvents"
}
});
// Startup router
App.addInitializer(function () {
console.log("communityApp.js: App.addInitializer()")
// contains active controller
communityApp.activeController = new communityApp.Controllers.tabController();
// initializing route
communityApp.Router = new Router({
controller: communityApp.activeController
});
});
// Let app know we started
communityApp.addInitializer(function () {
console.log("communityApp.js: DemoApp.addInitializer()");
App.vent.trigger("app:started", "communityApp");
});
// This will run when a sub app (module) starts
communityApp.on("start", function () {
console.log("communityApp.js: on 'Start'()");
});
code of controller is.
spine.module("communityApp", function (communityApp, App, Backbone, Marionette, $, _) {
"use strict";
// initializing controllers and collections for message tabs
communityApp.Controllers = {};
communityApp.Collections = {};
communityApp.Controllers.tabController = Marionette.Controller.extend({
showCommunityTab: function () {
this.getCommunityTab();
},
getCommunityTab: function (data) {
//var tabLayout = new communityApp.Views.tabLayout();
//tabLayout.render();
// creating active layout
communityApp.activeTabLayout = new communityApp.Views.tabLayout();
communityApp.activeTabLayout.render();
// loading community module view
App.regionMain.show(communityApp.activeTabLayout);
// load pforum on community module load
this.getPforum();
},
getPforum : function(){
console.log('Public Forum Tab');
var pforum = new communityApp.Controllers.pforumController();
pforum.init();
},
getQuestions : function(){
console.log('Question tab');
var questions = new communityApp.Controllers.questionsController();
questions.init();
},
getEvents : function(){
console.log('Events tab');
var events = new communityApp.Controllers.eventController();
events.init();
}
});
Code where error is, Its a tab page.
spine.module("communityApp", function (communityApp, App, Backbone, Marionette, $, _) {
"use strict";
communityApp.Controllers.pforumController = Marionette.Controller.extend({
init: function(){
var func = _.bind(this._getPforum, this);
$.when(App.request('alerts1:entities' , {origin:'pforum'}))
.then(func)
},
_getPforum:function(data){
// populating the data
communityApp.activeTabLayout.pforum.show(new communityApp.CollectionViews.pforumCollectionViews({
collection: data
}));
}
});
That's because you're creating the activeTabLayout in getCommunityTab, and you're trying to access it after creating the controller in getPforum. These are both attached to separate routes. Therefore you're not guarenteed that communityApp.activeTabLayout exists inside of your init method.
community/pforum -> creates your controller, but not your tab layout.
community -> creates your tab layout, but not your controller.
You need to make sure communityApp.activeTabLayout = new communityApp.Views.tabLayout(); runs before pforum.init();
I have my application set up in the following way. It does not allow me to trigger any "java-script routes"- after loading the page-- after I navigate to this page with a sub-domain extension to the url I enter.
//Create App
App = new Backbone.Marionette.Application();
//APP Regions
App.addRegions({
displayRegion: "#displayRegion"
});
//Routing controller
someController = {
usersarea: function () {
App.displayRegion.show(userList_ITEM);
alert('Users');
},
login: function () {
App.displayRegion.show(login_view);
alert('Login View');
}
};
//Router
MyRouter = new Marionette.AppRouter({
controller: someController,
appRoutes: {
"users": "usersarea",
"login": "login",
}
});//MyRouter
// Application Views
userList_ITEM_proto = Backbone.Marionette.ItemView.extend({
template: "#userList_ITEM"
});
login_view_proto = Backbone.Marionette.ItemView.extend({
template: "#login_view"
});
//Before STARTS
App.on('initialize:before', function () {
if (!Backbone.History.started) Backbone.history.start();
alert('It works');
login_view = new login_view_proto;
userList_ITEM = new userList_ITEM_proto;
});
//After START
App.on('initialize:after', function (options) {
console.log('Initialization Finished');
});
//At Start
App.on('start', function (options) {
alert('It works');
});
App.start();
You're trying to use view instances in someController before you've instantiated them.
http://jsfiddle.net/ddL4n/28/
You have a number of dependency issues in this script and should consider using Marionette's modules or Require.js to manage them.
I am new to backbone js and i wanted to call one external url and i want the which will fetch from the url output.
I have tried like the following
var MyApp.myModel = Backbone.Model.extend({
url: 'http://senthil_c/DSCFrameWork/UVIndevSvc.svc/GetWeatherByZipcode/02111/json'
});
var MyApp.myView = Backbone.View.extend({
initialize: function() {
this.model.bind("change",this.render,this);
this.model.fetch();
},
render: function() {
alert('do awesome stuff here');
}
});
I dont know how to call and i dont know this one is correct or not any one suggest me?
initialize: function() {
this.model = new MyApp.myModel();
this.model.fetch();
}
I have an application using backbone but whenever I call the fetch() method for the collection it returns undefined:
// App
(function () {
window.app = {};
app.collections = {};
app.models = {};
app.views = {};
$(function () {
app.collections.complaintTypes = new app.collections.ComplaintTypesCollection();
app.views.complaintTypesView = new app.views.ComplaintTypesView({ collection: app.collections.complaintTypes });
});
})();
// Collections
(function (collections, model) {
collections.ComplaintTypesCollection = Backbone.Collection.extend({
initialize: function () {
this.fetch();
},
model: model,
url: '/api/ComplaintTypes'
});
})(app.collections, app.models.ComplaintType);
// Models
(function (models) {
models.ComplaintType = Backbone.Model.extend({
idAttribute: 'ComplaintTypeId'
});
})(app.models);
// Views
(function (views) {
views.ComplaintTypesView = Backbone.View.extend({
initialize: function () {
this.collection.on('reset', this.render, this);
},
render: function () {
console.log(this.collection);
}
});
})(app.views);
But this doesn't return anything? If I use fiddler and go to my URL: /api/ComplaintTypes I do retrieve data back so I'm not sure what Im doing wrong here?
Deleting "model" line in the collection file worked for me.
Fetch is async. If you need to get the results, you need to pass a "success" handler, i.e.:
function myHandler(models) {
}
...
this.fetch({success: myHandler});
I think the problem is that you create the view while the collection has not been fetched yet (because of JS's asynchronous behavior). Try this way:
$(function () {
app.collections.complaintTypes = new app.collections.ComplaintTypesCollection();
app.collections.complaintTypes.fetch({success:function(){
app.views.complaintTypesView = new app.views.ComplaintTypesView({ collection: app.collections.complaintTypes });
}});
});
And remove the initialize function from your collection.
Alright, so here is my main backbone code
(function ($) {
var Job = Backbone.Model.extend({});
var JobList = Backbone.Collection.extend({
model: Job,
url: "/api/jobs?format=json"
});
var JobView = Backbone.View.extend({
el: $('#jobs'),
_templatesrc: $("#job-template").html(),
_template: {},
initialize: function () {
var self = this;
_.bindAll(this, 'render');
//create the template
this._template = Handlebars.compile(this._templatesrc);
//setup data
this.collection = new JobList();
//response function from server query
var response = function () {
console.log(arguments);
self.render();
};
var response2 = function () {
console.error(arguments);
self.render();
};
this.collection.fetch();
},
render: function () {
console.log("models", this.collection.models);
$(this.el).html(this._template(this.collection.models));
}
});
var view = new JobView();
})(jQuery);
When i do this.collection.fetch() i get nothing. When i do this.collection.fetch({ success:response, error:response2}); the following error is thrown:
Backbone.View.extend.initialize.response2 app.js:29
g.wrapError backbone-min.js:104
f.Callbacks.o jquery.min.js:2
f.Callbacks.p.fireWith jquery.min.js:2
w jquery.min.js:4
f.support.ajax.f.ajaxTransport.send.d
In chrome i can tell that it returns a JSON response though, which looks like
[{"Client":"hi",
"ReporterTime":"\/Date(-62135578800000-0500)\/",
"TimeTaken":PT0S,
"Status":"Start"}]
Any ideas on why Backbone isn't turning my JSON response into the collection?
Unless I'm mistaken PT0S is not valid JSON. Try to return it wrapped in quotes:
[{"Client":"hi",
"ReporterTime":"\/Date(-62135578800000-0500)\/",
"TimeTaken":"PT0S",
"Status":"Start"}]
I've just fixed support for TimeSpans in ServiceStack.Text's JsonSerializer.
Will be available from v3.94+ on NuGet or GitHub.