I am following a backbone.js tutorial and a part of the code isn't working, maybe because Backbone has changed in the meantime or because I'm doing something wrong. This is the render function of my view.
// grab and populate our main template
render: function () {
// once again this is using ICanHaz.js, but you can use whatever
this.el = ich.app(this.model.toJSON());
// store a reference to our movie list
this.movieList = this.$('#movieList');
return this;
},
The element gets appended into the document later in the code. Subsequently, when the code tries to adds elements to this.movieList, Javascript says it's undefined.
I have tried changing this.el = ... to
this.setElement(ich.app(this.model.toJSON()));
and that helps because this.$el is now defined, but if i try this.$el.find(...) it never finds anything, even though through inspection in Chrome it does appear to contain the HTML elements.
I never used ICanHaz but it it works like the other template languages probably returns HTML code. In that case i'd do something like:
render: function(){
this.$el.html(ich.app(this.model.toJSON()));
}
addMovie: function (movie) {
var view = new MovieView({model: movie});
this.$el.find("#movieList").append(view.render().el);
},
Hope this helps
PS: This is the first time I see this.$('something') in a backbone code o_O. Is he storing the reference of JQuery on the view?
Related
There are Two implementation I am confused between :-
- **FIRST**
// A self invoking function
selfFunction = (function(){
$(document).ready(function(){
applyBindings();
});
applyBindings = function(){
$("#btnSubmit").on("click",function(){//Do Something});
.....
.....
.....
//More Bindings
};
})();
- **SECOND**
// A self invoking function
selfFunction = (function(){
applyBindings();
applyBindings = function(){
$("#btnSubmit").on("click",function(){//Do Something});
.....
.....
.....
//More Bindings
};
})();
The Only difference is that in FIRST case I am binding the events using $(document).ready(). Where as in SECOND I am calling a function inside a Self invoking function.
Both are getting the work done, but I want to know which one should be followed and why??
The difference is that using $(document).ready(callback) will work even if your js file was loaded (leading to the IIFE being executed) before the elements you apply bindings to had been rendered. (Maybe because some complex page structure, slow loading pictures or something similar).
Like the name suggests, $(document).ready(callback), guaranties that your function will not run until the document is.. ready. So you can be sure that, for example, the element with id btnSubmit exists. (Assuming it's part of the original HTML, ie. not being dynamically created elsewhere in the code).
To be clear, this
$("#btnSubmit")
is the part where it could break down. Beacuse if the button doesn't exist yet, then it doesn't matter that the click will definitely not come before the button exists. The event-listener specified by the rest of the code following $("#btnSubmit") (ie the .on("click", callback)) will not be applied to the button, because there is no button (yet).
So the $(document).ready(callback) version is safer in more circumstances.
I wanna know if there is a way to call a function after rendering the view by backbone. The problem is that, the function I want to call need an html element rendered by backbone. indeed, I'm using 'ipywidgets' python module, which allows the creation of custom widgets which are exactly backbone views.
Here is the view code:
var TestView = widget.DOMWidgetView.extend({
render: function() {
var template = _.template( $("#editor_template").html(), {} );
this.$el.html(template);
this.model.on('change:value', this.backToFront, this);
//return this;
},
backToFront: function() {
//$("#editor").val(this.model.get('script_ldp'))
editor.getSession().setValue(this.model.get('value'));
console.log("python change value " + this.model.get('value'));
},
events: {'click':'frontToBack'},
frontToBack: function(event){
this.model.set('value', editor.getSession().getValue());
this.touch();
console.log("js change value " + this.model.get('value'));
}});
this piece of code will display an html textarea on the page, and after-done, I should transform this textarea to something else(ace editor) by getting it from the DOM by it's 'id'.
If I do that: document.getElementById('textarea_id_returned_by_render') it returns null. I also tried that by it didn't work for me, it can be because of the python module I'm using, I mean that I'm not using pure backbone.js.
if you have an onRendered callback, you can log the this to get the template.
Template.myTemplate.onRendered(function () {
console.log(this);
});
For debugging purposes, in the javascript console, is it possible to get the current rendered template via some sort of script? Eg:
> var ctx = Template.myTemplate // something like this
In Chrome (and possibly other browsers), after you console.log an object, you can right click on the output in the JavaScript console and click "Store as global variable". That will assign it to a variable (named temp1, temp2, and so on). You can then access that object through the new variable.
Also in Chrome, selecting an element in the developer tools makes it available in the JavaScript console as $0. If you define the following function globally:
getTemplateInstance = function (elem) {
var view = Blaze.getView(elem);
while (!view.templateInstance) {
view = view.parentView;
}
return view.templateInstance();
}
Then you can get any rendered template instance by following these steps:
Right click somewhere on the template
Click "Inspect element"
In the developer tools, switch to the JavaScript console
Enter getTemplateInstance($0) to get the template instance.
If you're careful to only select an element at the top level of the template (not inside a {{#if}}, {{#each}}, etc.) then you can skip the getTemplateInstance function and just run Blaze.getView($0).templateInstance() in the console.
You can also use Blaze.getData($0) to get the data context of an element.
Because its possible to have two of the same template you have explicitly pass on its reference to a global variable.
ctx = null;
Template.myTemplate.onRendered(function () {
ctx = this;
});
This should let you use 'ctx' anywhere. It depends a lot on where you use it, you can get the template instance in events or helpers you can get the template instance from within its own helpers or events:
Template.myTemplate.events({
'click #something': function(e,tmpl) {
console.log(tmpl) //The template instance
console.log(Template.instance()) //just like tmpl
}
});
Template.myTemplate.helpers({
'somehelper': function() {
console.log(Template.instance());
}
});
I am new to Knockoutjs and JavaScript, and need some advice.
In my HTML (View) page, I am trying to show a text property from my Javascript object (Model), which looks something like:
var object = function() {
this.text = "blah blah blah";
}
In my Object's ViewModel, I have this:
var objectViewModel= function (object) {
var content = ko.observable(object); // or is it object.text() ?
self.section = function() {
return content.text; //or is it content ?
}
}
And in my view, I have this:
<span data-bind="text:section"></span>
My main question is how do I make the HTML show a model's property (the text) via viewmodel? I commented in my other questions, and would like some help.
Thanks in advance!
So I'd recommend this post as a good read.
To answer both of the additional commented questions: It all depends on what you passed as the parameter. That important bit of information would be provided when you instantiate your viewmodel, which you left out.
As specified, you'll need to ko.applyBindings(new objectViewModel(new object())).
Secondly, you have self, where did it come from? Make it this or declare var self = this; or provide the rest of the code from which that variable is coming from.
Next, from within the section function you need to "read" your content observable:
return content().text
Finally, in your view you need to execute section:
<span data-bind="text:section()"></span>
As an additional consideration, you could make section a computed observable with a dependency on content.
this.section = ko.computed(function() {
return content().text;
})
which removes the need to execute in the view. Check out this fiddle with two different scenarios depicted.
https://gist.github.com/stephenvisser/2711454
I use this gist for navigation.
I have a view as follows. This view is for a dom (#blog-list-container) inside a template. template is loaded with the gist navigation.
app.BlogListView = Backbone.View.extend({
el: '#blog-list-container',
renderBlog: function(item) {
var blogView = new app.BlogShortView({
model: item
});
this.$el.append(blogView.render().el);
},
render: function() {
this.collection.each(function(item) {
this.renderBlog(item);
}, this);
}, ....
I create this view and navigation as follows:
new Navbar({el:$('#nav-item-container')});
new Content({el:$('#container')});
new app.BlogListView();
So the problem is, this.el is undefined inside BlogListView. In my opinion; it doesn't pick up the dom el: #blog-list-container because it is inside the template and loaded after BlogListView is initialized. How can i overcome this?
This is my first backbonejs experiment, i hope this makes sense.
EDIT:
It works fine if i use jquery selector
$('#blog-list-container').append(blogView.render().el);
But i still want to know what is the proper way to set the el property.
As #mu is too short advised, don't use that Backbone.js too, it isn't the best practice. Yes, you are running into the fact that it tries to append the element before it is fully rendered to the DOM.
I have never once used that first options and have never run into these kinds of problems, so I advise against it.
And I believe you left out a #:
$('#blog-list-container').append(blogView.render().el);
Juts add
return this;
at the end of your "render" function.
Your call this.$el.append(blogView.render().el); expects to have element "el" returned and you are not returning anything, (notice .el() part at the end of your call), so jQuery throws "undefined" error because there is nothing to return.