Mootools detecting partial dom change event - javascript

Good morning,
i have a mootools class with the event 'beforeunload' associate to the window object.
i need to add similar event when my partial dom container change/remove.
There is a way to intercept this event?
This is my class code:
var Push = new Class({
Implements: [Events],
attachPushClassEvents: function() {
var self = this;
window.addEvent('beforeunload', function(event){
// do something
});
},
initialize : function(domContainer) {
this.container = domContainer;
self.attachPushClassEvents();
}
});
Thanks in advance

Related

JavaScript: using THIS inside object function and binding event

I have an Object and I want to bind a function to a button when Object was initialized.
var MyClass = {
Click: function() {
var a = MyClass; // <---------------------- look here
a.Start();
},
Bind: function() {
var a = document.getElementById('MyButton');
a.addEventListener('click', this.Click, false); //<---------- and here
},
Init: function() {
this.Bind();
}
}
So, I'm new at using it and I don't know if object can be declared like this (inside Click() function that should be done after clicking a button):
Is it a bad practise? Which could be the best way in this case when adding an event here?
Edit: fiddle
Firstly you have a syntax error. getElementsById() should be getElementById() - no s. Once you fix that, what you have will work, however note that it's not really a class but an object.
If you did want to create this as a class to maintain scope of the contained methods and variables, and also create new instances, you can do it like this:
var MyClass = function() {
var _this = this;
_this.click = function() {
_this.start();
};
_this.start = function() {
console.log('Start...');
}
_this.bind = function() {
var a = document.getElementById('MyButton');
a.addEventListener('click', this.click, false);
};
_this.init = function() {
_this.bind();
};
return _this;
}
new MyClass().init();
<button id="MyButton">Click me</button>
For event listeners it's easiest and best to use jQuery, for example if you want to have some .js code executed when user clicks on a button, you could use:
https://api.jquery.com/click/
I don't know how new you are to .js, but you should look up to codecademy tutorials on JavaScript and jQuery.
.click() demo:
https://www.w3schools.com/jquery/tryit.asp?filename=tryjquery_event_click

Marionette ItemView events after re-rendering

i'm playing with Marionette first time.
After re-rendering ItemViews, their events not triggered.
Simple example:
App = new Marionette.Application;
App.addRegions({
headerRegion: '#header',
contentRegion: '#content',
});
App.addInitializer(function () {
this.Views = {
MainMenu : new MainMenuView(),
ContentOne : new ContentOneView(),
ContentTwo : new ContentTwoView(),
};
});
App.addInitializer(function () {
var self = this;
var eva = self.vent;
eva.listenTo(self.Views.MainMenu, 'content1', function () {
self.contentRegion.show(self.Views.ContentOne);
});
eva.listenTo(self.Views.MainMenu, 'content2', function () {
self.contentRegion.show(self.Views.ContentTwo);
});
});
App.on('start', function () {
var self = this;
self.contentRegion.show(self.View.ContentOne);
});
App.start();
After re-rendering ContentOneView & ContentTwoView, their events not triggered.
What i'm doing wrong?
The problem you are having is that region.show() is going to close any view that is currently occupying that region. Doing so undelegates the view's events. After the initial region.show() you should manually call render on the view.
You can see this explained here and an issue discussing it here.
I managed to solve this problem by using delegating the events when the view is shown in the layout:
layoutView.content.show(contentView);
contentView.delegateEvents();
Although this is only necessary after the first render as mentioned by Andrew Hubbs
instead of using eva to listen to events that happen on the views, try listening to eva for events passed by other views
App.addInitializer(function () {
var eva = self.vent;
var self = this;
this.listenTo(eva, 'someStringHere', function(){/*do stuff here*/};
});
and then in your views you can trigger events through eva/vent
var eva = self.vent;
eva.trigger("someStringHere");

Passing Data to event handler in Backbone View

I'm developing a web app using Backbonejs.
I have a use case where I have to pass the new position of div1 to a double click event handler of a Backbone view.
My code looks like
var MyView = Backbone.Views.extend({
events: {
'dblclick #div1' : 'div1ClickHandler' //here I want to pass new offset for #div1
}
});
div1ClickHandler: function()
{
......
}
var myView = new MyView({model: myModel,el : #div1});
You can do that: inside div you need to add a new field with name data-yourfieldName and from js call that:
yourFunctionName: function(e) {
e.preventDefault();
var email = $(e.currentTarget).data("yourfieldName");
}
Assuming that your view element is a child element of the jquery widget, the best thing is probably to grab the values you need in the click handler:
var MyView = Backbone.Views.extend({
events: {
'dblclick #div1' : 'div1ClickHandler'
}
});
div1ClickHandler: function()
{
var $this = $(this);
var $widget = $this.parents('.widget-selector:first');
$this.offset($widget.offset());
$this.height($widget.height());
$this.width($widget.width());
}
var myView = new MyView({model: myModel,el : #div1});
If the jquery widget is always the direct parent of your view element, you can replace parents('.widget-selector:first') with parent(); otherwise, you'll need to replace .widget-selector with a selector that will work for the jquery widget.
You can pass widget in view itself, then you will have full control over widget.
var MyView = Backbone.Views.extend({
initialize: function(options) {
this.widget = options.widget; // You will get widget here which you passed at the time of view creation
}
events: {
'dblclick #div1' : 'div1ClickHandler' //here I want to pass new offset for #div1
}
});
div1ClickHandler: function() {
// Query to fetch new position and dimensions using widget
// update the respective element
}
var myView = new MyView({model: myModel, el: $('#div1'), widget: widgetInstance});

Javascript MVC + listening and dispatching events with jQuery

I'm learning javascript and have a question about listening and dispatching events with jQuery.
In my Model, I have a function that triggers a change event:
Model.prototype.setCurrentID = function(currentID) {
this.currentID = currentID;
$('body').trigger('change');
}
The trigger event requires an element, so I bound it to the 'body'. Is this good practice or bad practice?
In AS3, which I'm more familiar, I would simply dispatch a global event from the model, passing in a const value, listening for this event with an instance of the Model:
var model:Model = new Model();
model.addEventListener(CONST_VALUE, handlerFunction);
In jQuery, within my View object, I need to attach an element to the listener as well, so I bound it to the 'body' once again:
var View = function(model, controller) {
var model;
var controller;
this.model = model;
this.controller = controller;
$('body').change(function(evt) { updateSomething(evt); });
function updateSomething(evt){console.log('updating...')};
}
It's working, but I'm interested in your take on the subject.
I recommend using a private dispatcher, something that isn't exposed to the public.
For instance, your logic may fail if the user or a plugin unbinds all the events on the body(your dispatcher) :
$('body').unbind();
This can be avoided by creating a dom node and not expose it to the end user (do not append it to the dom) :
var dispatcher = $('<div />');
Model.prototype.setCurrentID = function(currentID) {
this.currentID = currentID;
dispatcher.trigger('change');
}
var View = function(model, controller) {
this.model = model;
this.controller = controller;
dispatcher.bind('change',function(evt) { updateSomething(evt); });
function updateSomething(evt){console.log('updating...')}
}
Another good thing to have in mind when developing event-programming app with jQuery is that jQuery allows you to bind/trigger custom events and also allows you to namespace your events. This way you can control more efficiently the event binding and triggering :
Model.prototype.setCurrentID = function(currentID) {
this.currentID = currentID;
dispatcher.trigger('modelIdChange.' + this.currentID);
}
Model.prototype.destroy = function() {
// unbind all the event handlers for this particular model
dispatcher.unbind('.'+this.currentID);
}
var View = function(model, controller) {
/*...*/
// this will be triggered for all the changes
dispatcher.bind('modelIdChange',function(evt) { updateSomething(evt); });
// this will be triggered only for the model with the id "id1"
dispatcher.bind('modelIdChange.id1',function(evt) { updateSomething(evt); });
/*...*/
}
I'd go a step further and create custom global events. With jQuery you can trigger a global custom event like so:
$.event.trigger('change');
Any element can subscribe to that event:
$('#myDiv').bind('change', function() {
console.log($(this));
});
The this keyword in the event handler is the DOM element which subscribed to the triggered event.
My objections are:
I wouldn't bind events that have the same name as broswer events, there might be interferences.
Your code works if you have one model, but if you have 2 or more, you'd want to separate them, and not bind/trigger both on the same element.
How about:
Model.prototype.bind = function(event, func) {
if (!this._element) this._element = $('<div>');
this._element.bind(this.name+'_'+event, $.proxy(func, this));
return this;
};
Model.prototype.trigger = function(event) {
if (!this._element) this._element = $('<div>');
this._element.trigger(this.name+'_'+event);
return this;
};
This way you solve both. Note I'm appending this.name+'_' to event names (which assume each model has some sort of name, and makes sure events won't match with browser events), but you can also drop the the prefix.
I'm also using $.proxy in bind so that the this in the event handler refers to the model.
var View = function(model, controller) {
....
model.bind('change', function() {...});
}

Backbone.js views - binding event to element outside of "el"

The 2nd answer to this question nicely explains how event declarations in Backbone.js views are scoped to the view's el element.
It seems like a reasonable use case to want to bind an event to an element outside the scope of el, e.g. a button on a different part of the page.
What is the best way of achieving this?
there is not really a reason you would want to bind to an element outside the view,
there are other methods for that.
that element is most likely in it's own view, (if not, think about giving it a view!)
since it is in it's own view, why don't you just do the binding there, and in the callback Function,
use .trigger(); to trigger an event.
subscribe to that event in your current view, and fire the right code when the event is triggered.
take a look at this example in JSFiddle, http://jsfiddle.net/xsvUJ/2/
this is the code used:
var app = {views: {}};
app.user = Backbone.Model.extend({
defaults: { name: 'Sander' },
promptName: function(){
var newname = prompt("Please may i have your name?:");
this.set({name: newname});
}
});
app.views.user = Backbone.View.extend({
el: '#user',
initialize: function(){
_.bindAll(this, "render", "myEventCatcher", "updateName");
this.model.bind("myEvent", this.myEventCatcher);
this.model.bind("change:name", this.updateName);
this.el = $(this.el);
},
render: function () {
$('h1',this.el).html('Welcome,<span class="name"> </span>');
return this;
},
updateName: function() {
var newname = this.model.get('name');
console.log(this.el, newname);
$('span.name', this.el).text(newname);
},
myEventCatcher: function(e) {
// event is caught, now do something... lets ask the user for it's name and add it in the view...
var color = this.el.hasClass('eventHappened') ? 'black' : 'red';
alert('directly subscribed to a custom event ... changing background color to ' + color);
this.el.toggleClass('eventHappened');
}
});
app.views.sidebar = Backbone.View.extend({
el: '#sidebar',
events: {
"click #fireEvent" : "myClickHandler"
},
initialize: function(){
_.bindAll(this, "myClickHandler");
},
myClickHandler: function(e) {
window.user.trigger("myEvent");
window.user.promptName();
}
});
$(function(){
window.user = new app.user({name: "sander houttekier"});
var userView = new app.views.user({model: window.user}).render();
var sidebarView = new app.views.sidebar({});
});
Update: This answer is no longer valid/right. Please see other answers below!
Why do you want to do this?
Apart from that, you could always just bind it using regular jQuery handlers. E.g.
$("#outside-element").click(this.myViewFunction);
IIRC, Backbone.js just uses the regular jQuery handlers, so you're essentially doing the same thing, but breaking the scope :)

Categories

Resources