I use the backbone marionette in browserify.
I met a problem about showing view.
I have addRegions and want to show the ItemView.
But the console show error: Uncaught Error: An "el" #tmp_area must exist in DOM.
My HTML file have #tmp_area area.
When I use require.js it doesn't show this problem, but it happened when I change to use browserify.
I don't know what's wrong.
Below is my code.
app.js
var Backbone = require('backbone');
var $ = require('jquery');
Backbone.$ = $;
var Marionette = require('backbone.marionette');
var MyView = require('./views/my_view');
var app = new Marionette.Application();
app.addRegions({
tmp_area: "#tmp_area"
});
app.addInitializer(function() {
var myView = new MyView();
app.tmp_area.show(myView);
});
app.on("initialize:after", function() {
if (Backbone.history) {
Backbone.history.start();
}
});
app.start();
my_view.js
var $ = require('jquery');
var Backbone = require('backbone');
var Marionette = require('backbone.marionette');
var templates = require('../templates/tmp.hbs');
Backbone.$ = $;
module.exports = Marionette.ItemView.extend({
template: templates,
})
Please help me!
I do appreciate it!
I'm pretty sure that this is related to the document ready state. You can just put a script at the bottom of your HTML or wrap an application initialization step into document.ready function.
Related
Previously this will work but I've update the underscore and backbone to the latest version, then I got error of
Uncaught TypeError: this.$el.off is not a function
http://jsfiddle.net/mmm770v8/
SearchView = Backbone.View.extend({
initialize: function(){
this.render();
},
render: function(){
var template = _.template( $("#search_template").html(), {} );
this.el.html( template );
},
events: {
"click input[type=button]": "doSearch"
},
doSearch: function(){
// Button clicked
console.log(this.el.find('#search_input').val());
}
});
You have several problems:
Your fiddle was using jQuery 1.5.2 which is ancient and used bind/unbind instead of on/off. Backbone expects a more recent version of jQuery which has on and off functions.
You're using this.el where you mean this.$el. this.el is just a plain old DOM node, this.$el is the cached $(this.el).
The var html = _.template(tmpl, data) form of _.template went away in Underscore 1.7.0. You now need a two step process:
var t = _.template(tmpl);
var h = t(data);
so your render should look more like this:
render: function() {
var template = _.template($("#search_template").html());
this.$el.html(template({}));
}
Updated fiddle: http://jsfiddle.net/ambiguous/L5z4agh4/
This is my issue, I have an index.html page which loads the reCAPTCHA script explicitly:
<script src="https://www.google.com/recaptcha/api.js?onload=loadCaptcha&render=explicit" async defer></script>
I have a template which contains the reCAPTCHA container element (div):
<form id="payment-<%= model.Id %>" class="form" action="" method="POST">
...
<div class="captcha-container"></div> //not being used yet
</form>
And I have a backbone view which injects the template into index.thml:
'use strict';
var Backbone = require('Backbone');
var Validation = require('backbone-validation');
Backbone.Validation = Validation;
Backbone.$ = $;
module.exports = BaseView.extend({
events: {},
formView: null,
initialize: function (options) {
var loadCaptcha = function() {
window.alert('captcha is ready');
};
},
render: function () {
// renders view using my form template
}
});
At this point I'm unable to even trigger the callback function (loadCaptcha), my suspicion is that the issue lies in the load order, the index page is loaded and the "onload=loadCaptcha" event occurs before the backbone view is initialized. I've tried removing the "async" property from the script tag, but no luck. Any ideas of how I can get this to work?
I figured out the solution, by pulling in the recaptcha script directly from the view which renders it. Hope this helps someone in the future.
loadCaptcha: function() {
var self = this;
var getRecaptchaResponse = function(response) {
self.captchaResponse = response;
};
var renderCaptcha = function() {
self.captchaWidgetId = grecaptcha.render('recaptcha-container-' + self.model.get('Id'), {
sitekey : service.settings.recaptchaSiteKey,
callback: getRecaptchaResponse
});
};
window.renderCaptcha = renderCaptcha;
$.getScript('https://www.google.com/recaptcha/api.js?onload=renderCaptcha&render=explicit', function() {});
},
I would put your captch script in a backbone view. Then put it in the render of your main view. Like that it's modular you have a main view and a subview containing the captcha which is loaded when the main view is rendered.
Getting this odd error when using node-webkit, here is a complete example which can recreate it:
index.js:
var jQuery = require('jquery');
var Backbone = require('backbone');
(function($){
var ListView = Backbone.View.extend({
el: $('body'),
initialize: function(){
_.bindAll(this, 'render');
this.render();
},
render: function(){
$(this.el).append("<ul> <li>hello world</li> </ul>");
}
});
var listView = new ListView();
})(jQuery);
index.html:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="./css/main.css" />
</head>
<body>
</body>
<script src="./js/index.js"></script>
</html>
The stack trace:
TypeError: Expecting a function in instanceof check, but got undefined
at _.extend.setElement (C:\SVN\mapthing\branches\mapthing_js\node_modules\backbone\backbone.js:1046:45)
at _.extend._ensureElement (C:\SVN\mapthing\branches\mapthing_js\node_modules\backbone\backbone.js:1108:14)
at Backbone.View (C:\SVN\mapthing\branches\mapthing_js\node_modules\backbone\backbone.js:1000:10)
at new child (C:\SVN\mapthing\branches\mapthing_js\node_modules\backbone\backbone.js:1566:41)
at file:///C:/SVN/mapthing/branches/mapthing_js/js/index.js:18:18
at file:///C:/SVN/mapthing/branches/mapthing_js/js/index.js:19:3
Having trouble seeing where my problem is?
Most solutions seem to point to having to require jquery first, but I have done this...
I'm a relative n00b so I'm expecting ive done something very daft...
This is a hack, so be warned of that, but the error is coming from this method in the backbone lib (node_modules/backbone/backbone.js:1046 from your stacktrace):
setElement: function(element, delegate) {
if (this.$el) this.undelegateEvents();
this.$el = element instanceof Backbone.$ ? element : Backbone.$(element);
this.el = this.$el[0];
if (delegate !== false) this.delegateEvents();
return this;
},
Most likely you can circumvent this error by explicitly setting jQuery on Backbone, like this:
var jQuery = require('jquery');
var Backbone = require('backbone');
Backbone.$ = jQuery;
That is a totally untested guess, but it should work.
I think this is just a JavaScript scope question.
I'm trying to add some Jasmine tests to a Backbone application, but I can't figure out how to access Backbone models from within my Jasmine setup.
This is my current application structure (main.js is my Backbone application):
index.html
js/
main.js
vendor/
backbone.js
jquery.min.js // etc
tests/
SpecRunner.html
spec/
testSpec.js
The content of main.js is like this, and it's all running OK from index.html:
$(function(){
var Todo = Backbone.Model.extend({
defaults: function() {
return {};
},
... etc
The files in SpecRunner.html look like this:
<!-- include source files here... -->
<script src="/js/vendor/jquery-1.10.2.min.js"></script>
<script src="/js/vendor/underscore.js"></script>
<script src="/js/vendor/backbone.js"></script>
<script src="/js/main.js"></script>
<!-- include spec files here... -->
<script type="text/javascript" src="spec/testSpec.js"></script>
I have written this test in testSpec.js, but it's failing with ReferenceError: Todo is not defined:
describe("Todo tests", function(){
var todo = new Todo("Get the milk", "Tuesday");
it("should be correctly defined", function(){
expect(todo).toBeDefined();
});
it("should have the correct title", function(){
expect(todo.title).toBe("Get the milk");
});
});
How can I get hold of the Todo scope? I've tried window.Todo but that doesn't help either.
As we can see at the Backbone reference.
constructor / initialize new Model([attributes], [options])
When creating an instance of a model, you can pass in the initial values of
the attributes, which will be set on the model.
The constructor needs to be initilized with a object literal(Key value pair), as follow:
new Book({
title: "One Thousand and One Nights",
author: "Scheherazade"
});
So you need to change your code to:
var todo = new Todo({
task: "Get the milk",
dayOfWeek: "Tuesday"
});
UPDATE:
Here you declared the Todo inside the jquery function scope and you're trying to access from outside.
$(function(){
var Todo = Backbone.Model.extend({
defaults: function() {
return {};
},
etc...
}
}
You have two options, declare Todo as global, not recommend, but largely used at backbone samples:
$(function(){
window.Todo = Backbone.Model.extend({
defaults: function() {
return {};
},
etc...
}
});
You could also try to call the jquery function after declaration:
$(function(){
var Todo = Backbone.Model.extend({
defaults: function() {
return {};
},
etc...
}
})();
I have been going thru this book "developing backbone.js application"
where on page 18 theres a model function which goes like this:
(function($){
var Photo = Backbone.Model.extend({
defaults: {
'src': 'placeholder.jpg',
'title':'an image placeholder',
'coordinates':[0,0]
},
initialize:function(){
this.on("change:sr", function(){
var src = this.get("src");
console.log("Image src has been updated to: "+src);
});
},
changeSrc: function(source){
this.set({'src':source});
}
});
var somePhoto = new Photo({'src':'test.jpg', 'title':'testing'});
somPhoto.changeSrc('thatPhoto.jpg');
})(jQuery);
Its give me an error as
TypeError: this.on is not a function
this.on("change:src", function(){
on console.
Any Idea how i may solve this problem. I'm entirely new to Backbone.js.
Any Help is appreciated.
You might be using an old version of Backbone. on/off were only added on 0.9.0, before that they were called bind and unbind.
You should update to the latest Backbone (0.9.9 at the time of writing).