I'm writing a simple message board app to learn backbone. It's going ok (a lot of the use of this isn't making sense) but am a little stuck in terms of how I would remove a form / html from the dom. I have included most of the code but you can see about 4 lines up from the bottom, the part that isn't working. How would I remove this from the DOM?
thx in advance
var MbForm=Backbone.View.extend({
events: {
'click button.add-new-post': 'savePost'
},
el: $('#detail'),
template:_.template($('#post-add-edit-tmpl').html()),
render: function(){
var compiled_template = this.template();
this.$el.html(compiled_template);
return this;
},
savePost: function(e){
//var self=this;
//console.log("I want you to say Hello!");
data={
header: $('#post_header').val(),
detail: $('#post_detail').val(),
forum_id: $('#forum_id').val(),
post_id: $('#post_id').val(),
parent_id: $('#parent_id').val()
};
this.model.save(data, {
success: function(){
alert('this saved');
//$(this.el).html('this is what i want');
this.$el.remove();// <- this is the part that isn't working
/* none of these worked - error Uncaught TypeError: Cannot call method 'unbind' of undefined
this.$el.unbind();
this.$el.empty();
this.el.unbind();
this.el.empty();
*/
//this.unbind();
//self.append('this is appended');
}
});
Backbone doesn't call the success callback with any particular this, it is simply called as a plain function. So, this inside your success callback will be window rather than the view you're expecting it to be.
Any of the usual solutions will work:
Save the desired this in a local variable:
var _this = this;
this.model.save(data, {
success: function() {
//...
_this.remove();
Use a bound function:
this.model.save(data, {
success: _(function() {
//...
this.remove();
}).bind(this)
Use a named bound function:
initialize: function() {
_.bindAll(this, 'save_success');
}
//...
this.model.save(data, {
success: this.save_success
And the usual variations on the above.
Also note that I switched to View#remove since you are apparently trying to remove the whole view and that's the usual way to do it.
Related
I need to access a js variable declared in one block of a html page into another block of the same html page just so I can stop a ajax call that is being made, but I don't know how can I access a variable that was declared into another block. I can't merge the two blocks, everything else is on the table.
<script>
$(function() {
var term = new Terminal('#input-line .cmdline', '#container output');
term.init();
});
</script>
<script>
term.ajaxHandler.abort();//but how can I access the variable term from the block above,this will be inside a button later
</script>
Thanks in advance
The way your code example is described, it's not possible to reuse that variable. Because it is not bound to the window object, it's bound to the function that is self-executed. It's an example of a "safe" way of libraries not intervening with your own code.
You can however, since I guess by the syntax it's jQuery, hook into the jQuery ajax handling. Based on your requirements, to stop an ajax call, you need to listen to all ajax requests.
You could take a look at the jQuery ajax hooks, https://api.jquery.com/category/ajax/.
You could end up with something like:
$(document).ajaxSend(function(event, xhr, settings){
if (settings.url === "/your/url/to/abort") {
xhr.abort();
}
});
just declare var term above the function declaration
var term
function test1(){
term = 'hello there'
test2()
}
function test2(){
console.log(term)
}
test1()
ok, I managed to solve, basically I created a function only to abort the ajax request like this:
this.abortAjax = () => {
requestHandler.abort();
}
and then accessing it within terminal.js itself using the term object that was instantiated beforehand. After working around the code I was able to keep everything inside the terminal script and not splitted in the two parts, getting something like this:
function ShowLoadingScreen () {
var customElement = $("<div>", {
"class" : "btn btn-danger btn-lg",
"text" : "Abort",
"onclick": "term.abortAjax()"
});
$.LoadingOverlay("show", {
//image : "/static/loading.gif",
background : "rgba(204, 187, 0, 0.8)",
imageAnimation : "rotate_right",
//imageAutoResize : true,
text : "Loading...",
custom : customElement
});
}
function request (command) {
...
requestHandler = $.ajax({
url: _url,
beforeSend: function () { ShowLoadingScreen(); }, // <Show OverLay
type: 'GET',
dataType: 'json',
success: function (response) {
...
},
complete: function () { HideLoadingScreen(); } //<Hide Overlay
}).fail(function (jqXHR, textStatus, error) {
...
});
ShowLoadingScreen();
}
Thanks, everyone.
I created a view and has the ff codes:
var app = app || {};
app.singleFlowerView = Backbone.View.extend({
tagName: 'article',
className: 'flowerListItem',
// tells where to apply the views
template: _.template( $("#flowerElement").html() ),
// render
render: function(){
var flowerTemplate = this.template(this.model.toJSON());
// el contains all the prop above and pass to backbone
this.$el.html(flowerTemplate);
return this;
},
events: {
'mouseover': 'addBgColor',
'mouseout': 'removeBgColor'
},
addBgColor: function(){
this.$el.addBgColor('bgColorImage');
},
removeBgColor: function(){
this.$el.removeBgColor('bgColorImage');
}
});
When I run this to my HTML file I got the error addBgColor and removeBgColor is not a function. I have the CSS for this and all the models and views were set up.
Am I missing something here? Any idea why events doesn't work?
this.$el.addBgColor is the problem.
The events are triggering but you're calling addBgColor on the $el jQuery object, which is not a jQuery function, like the error message is telling you.
Check what's the difference between $el and el.
Tony, your events are cool and they are running they're just not doing anything.
this.addBgColor() will call your function in a view.
this.$el is referring to the html and there's no property called addBgColor assigned to $el.
You need to do something like change the class on your tag with the functions like so...
addBgColor: function(){
this.$el.className = 'bgColorImage'
},
.bgColorImage {
background-image: url('bgColorImage.jpg');
}
Basically, I'm trying to do something like this:
Person = Backbone.Model.extend({
validate: { ... },
initialize: function(){
this.bind('error', ?......?); <== what do I put?
},
// I DON'T WANT TO CALL THIS ONE
handleError: function(){ }
});
ViewOne = Backbone.View.extend({
//I WANT TO CALL THIS ONE:
handleError: function(model, error){
//display inside segmented view using jQuery
};
});
I tried options.view.handleError but it doesn't work...
My main purpose: I want a specific View that created the model to handle the error, not have the model to globally handle it all. For example, I want View#1 to do an alert while I want View#2 to display in a div. I don't know if this is the right way of doing it. If not, I would be gladly accept your help.
Thank you.
UPDATE: here's my jsFiddle
http://jsfiddle.net/jancarlo000/87mAk/
Since Backbone 0.5.2 it is recommended to drop bindAll in favor of third argument to bind if you need to pass the context.
ViewOne = Backbone.View.extend({
initialize: function() {
this.model.on('error', this.handleError, this);
},
handleError: function(model, error) { /* ... */ }
});
...
var person = new Person();
var viewone = new ViewOne({model : person});
General note here is that Models should never know about their Views. Only Views should subscribe to Model events.
You have it backwards, the view should be binding to the model's events:
ViewOne = Backbone.View.extend({
initialize: function() {
_.bindAll(this, 'handleError');
this.model.bind('error', this.handleError);
},
handleError: function(model, error) { /* ... */ }
});
I have created a new backbone.js widget model which I hope to extend:
var Widget = Backbone.Model.extend({
constructor: function() {
console.log('Widget constructor called.');
}
});
Depending on the page a user views a number of widgets will be loaded via Ajax, so for each widget I will do something like this:
$.getScript('widgets/widget1', function(xhr){
var widget1 = new pieChartWidget();
widget1.render();
widget1.update();
});
Contents of "widgets/widget1":
$(function() {
var pieChartWidget = Widget.extend({
render: function(json) {
console.log('Widget render called.');
},
update: function(json) {
console.log('Widget update called.');
}
});
});
In my Firebug console I get "pieChartWidget is not defined". I know the Javascript is being loaded successfully, I just cannot extend the "Widget" model from it.
Your widget is defined within a function. So all variable declared there are only visible withing then functions scope.
$(function() {
var pieChartWidget;
// pieChartWidget is only visible here!
});
// pieChartWidget not visible here!
To have access to the widget from outside of the function you have to assign it to a global variable (eg. your applications namespace). You could also use window (not the preferred way).
Your code should work unchanged if you assign your widget to window like so:
$(function() {
window.pieChartWidget = Widget.extend({
render: function(json) {
console.log('Widget render called.');
},
update: function(json) {
console.log('Widget update called.');
}
});
});
Using Mootools 1.3.2
Code is as follows:
var DNReportAbuse = new Class({
Extends: DNUserDialog,
comment_id: null,
container: null,
initialize: function(classname)
{
var bindclass = $(document.body).getElements(classname);
bindclass.each(function(el) {
el.addEvents({
click: function() {
this.reportComment();
}.bind(this)
});
});
},
reportComment: function() {
this.preventDefault();
alert('hello');
return false;
}
});
The event does bind, and when "this.reportComment();" is replaced with "alert('hello world');" it works entirely ...
... but when "this.reportComment()" is used, I instead receive an error, which Firebug explains as "function this.reportComment() is not a function".
I imagine that my issue has something to do with referring to a class function outside of its proper scope, though I'm a bit confused as to why ... or how to solve the issue. The end goal is to achieve an on-click binding of the reportComment() function to all members of a css class (up to 20 per page). The difficulty is that referencing the reportComment() function with "this.reportComment()" results in an error claiming that the function does not exist, when it clearly does exist.
Looking through similar questions on Stack Overflow did not seem to answer this issue ... so asking in hopes that someone can point me in the right direction.
You have some problems with bind and events:
initialize: function(classname)
{
var bindclass = $(document.body).getElements(classname);
var _self = this; //var to store the 'real' this you will use
bindclass.each(function(el) {
el.addEvents({
click: function(event) { //pass the event
this.reportComment(event);
}.bind(_self) //'this' is referring to the inner each function callback
});
});
},
reportComment: function(event) {
event.preventDefault(); //preventDefault on the event, not on 'this'
alert('hello');
return false;
}