jQuery this context to point to the element in context - javascript

I have a situation using BS3 modal events and my app functionality is wrapped in object with exposed methods (reveal module pattern). I have event received from BS and I what my $this to point to the Event object instead of the App object.
I tried jquery this context with the jQuery proxy, which seems to be the best thing, but for some reason the things didn't worked for me
var globalAppDef = (function() {
function modalFilters() {
$('#filtersMore')
.on('show.bs.modal', (event) => {
const sourceElement = $(event.relatedTarget);
$(sourceElement.data().filters).removeClass('hidden');
})
/*
* Transfer the proper #this of the event outside the {globalAppDef} Object
*/
.on('hidden.bs.modal', $.proxy((event) => {
$(this).find(".form-list-items-1").addClass('hidden');
$(this).find(".form-list-items-1").addClass('hidden');
}, this));
}
return modalFilters: modalFilters
}
});
var globalApp = new globalAppDef();
globalApp.initialize();
$(document).ready(function () {globalApp.modalFilters()});
What I what to achieve is on the second hidden.bs.modal $this to point to my Modal, which is $('#filtersMore') element.

actually it it was the Arrow function the reason for that this stayed in the Object context.
That way worked:
.on('hidden.bs.modal', $.proxy(function (event) {
$(this).find(".form-list-items-1, .form-list-items-2").addClass('hidden');
}, $('#filtersMore')));

Related

Adding onselectionchange to vue

i'm trying to implement a text selection listener to display a toolbar for some custom options
<script>
export default {
name: "home",
created() {
document.onselectionchange = function() {
this.showMenu();
};
},
data() {
return {
...
};
},
methods: {
showMenu() {
console.log("show menu");
}
}
</script>
<style scoped>
</style>
but it still display that can't call showMenu of undefined, so i tried in this way:
created() {
vm = this;
document.onselectionchange = function() {
vm.showMenu();
};
},
so, nothing changed =(
i need to use this selectionchange because its the only listener that i can add that will handle desktop and mobile together, other method i should implement a touchup, touchdown and its not working for devices
Functions declared the classic way do have their own this. You can fix that by either explicitly binding this using Function.prototype.bind() or by using an ES6 arrow function (which does not have an own this, preserving the outer one).
The second problem is that if you have more than one of those components you've shown, each will re-assign (and thus, overwrite) the listener if you attach it using the assignment document.onselectionchange =. This would result in only the last select element working as you expect because it's the last one assigned.
To fix that, I suggest you use addEventListener() instead:
document.addEventListener('selectionchange', function() {
this.showMenu();
}.bind(this));
or
document.addEventListener('selectionchange', () => {
this.showMenu();
});
A third solution stores a reference to this and uses that in a closure:
const self = this;
document.addEventListener('selectionchange', function() {
self.showMenu();
});

Jquery executing/triggering same code on different events

I have this function onclick event of custom tag densitybtn='yes'
$("[densitybtn='yes']").on('click', function () {
var no_of_people = 0;
//calcdensity
$("[calcdensity='yes']").each(function () {
no_of_people = parseInt($(this).val()) + no_of_people;
});
var total_density = parseInt(carpetArea) / parseInt(no_of_people);
$("#densityVal").html(Myval);
});
Can i extend same code by extending it to $("[calcdensity='yes']").on('blur')
$("[calcdensity='yes']").on('blur').$("[densitybtn='yes']").on('click', function () {
});
Am not sure on executing same code on different events
Let me know is this method correct? or is there any alternative way available?
Define the function normally (not as an anonymous function) and pass the function to the event listeners
function listener() {
var no_of_people = 0;
//calcdensity
$("[calcdensity='yes']").each( function() {
no_of_people = parseInt($(this).val())+no_of_people;
});
var total_density = parseInt(carpetArea)/parseInt(no_of_people);
$("#densityVal").html(Myval);
}
$("[densitybtn='yes']").on('click', listener);
$("[calcdensity='yes']").on('blur', listener);
Nope, thats not a good practise.
Instead you can write a function for the second intent and call it on blur of $("[calcdensity='yes']").
You can bind multiple events using jQuery's .on() method by space-separating the event arguments.
$("[densitybtn='yes']").on('click blur', function() {
// actions to perform
})
You can bind events to multiple elements using jQuery's .add() method.
$("[densitybtn='yes']").add("[calcdensity='yes']").on('click blur', function() {
// actions to perform
})

durandaljs - how to query a DOM element from a widget after ready

I want to query a element in a durandaljs widget, when it's ready.
If i use the selector directly in the data-binding, the element will not be found:
html (no attached view):
<button id="myButton"></button>
<div data-bind="widget: { kind: 'myWidget', options: { btn: $('#myButton') } }"></div>
controller.js:
define(function (require) {
var ctor = function (element, settings) {
var btn = settings.options.btn;
// btn = $('#myButton'); // this will work, but i'm not sure if the DOM is
// currently ready in the constructor
btn.on("click", function () {
console.log("I want to be fired");
});
};
return ctor;
});
Whats the best way to query a DOM element from a durandal widget at start?
I'm not sure where the html fragment belongs to so there are two slightly different answers.
First I'd suggest that you don't pass in the btnas jQuery object ({btn: $('myButton')}) , when you're not sure that it already exists. It's probably better to pass in a selector {btn: '#myButton'} and let the widget figure out how to deal with it.
Does your widget have its own view.html and the button is defined inside? If that's the case than you should take a look at the viewAttached callback.
var ctor = function (element, settings) {
this.btn = settings.options.btn;
};
ctor.prototype.viewAttached = function (view){
var btn = $(this.btn, view);
if ( btn.length > 0 ) {
btn.on("click", function () {
console.log("I want to be fired");
});
}
}
If your widget doesn't have its own view.html than you should let the widget know by adding a view property to the settings object with a value of false.
Here's the paragraph from http://durandaljs.com/documentation/Creating-A-Widget/ that explains that.
Note: In some cases, your widget may not actually need a view. Perhaps it's just adding some jQuery behavior or applying an existing jQuery plugin to a dom element. To tell Durandal that there is no view to load and bind, add a view property to the settings object with a value of false inside your widget's constructor.
In that instance however you can only access elements that are already in the DOM when the widget is instantiated e.g.
var ctor = function (element, settings) {
settings.view = false;
this.btn = $(settings.options.btn);
if ( this.btn.length > 0 ) {
this.btn.on("click", function () {
console.log("I want to be fired");
});
}
};

Playing around with jQuery objects and variables

$('div#Settings ul li').click(function () {
var url, template;
var self = $(this);
if (!$(self).hasClass('selected')) {
var ContextMenu = CreateContext($(self));
var id = $(self).attr('id');
etc...
function CreateContext(item) {
var ContextMenu = $('div#ContextMenu');
if (!$(ContextMenu).length) {
$('<div id="ContextMenu"></div>').appendTo('body');
CreateContext(item);
}
$(ContextMenu).slideUp(150, 'swing', function () {
$(ContextMenu).insertAfter(item);
});
$(item).addClass('selected').siblings().removeClass('selected');
return $(ContextMenu);
}
On the first call to CreateContext(item) I cannot use the variable ContextMenu later in the .click code. However, if CreateContext is called twice, everything works fine. I am getting an undefined variable when i console.log(ContextMenu) the first time. The second time it gets the object correctly. How can I fix this? Thanks.
That's because div#ContextMenu doesn't exist the first time you call CreateContext. In fact your function detects that condition and then creates it. But, after creating it, you don't populate the value of ContextMenu inside your function so the rest of the function doesn't work properly.
Here's what I would suggest:
function CreateContext(item) {
var ContextMenu = $('#ContextMenu');
if (!ContextMenu.length) {
ContextMenu = $('<div id="ContextMenu"></div>');
ContextMenu.appendTo('body');
}
ContextMenu.slideUp(150, 'swing', function () {
ContextMenu.insertAfter(item);
});
$(item).addClass('selected').siblings().removeClass('selected');
return ContextMenu;
}
Note, once ContextMenu is a jQuery object, you don't have to surround it with $() after that as it's already a jQuery object.
Try taking the jQuery indicator out of your function. Since you've declared the variable as a jQuery object, I don't believe you need to identify it as a jQuery object AGAIN in your function.

Using variable for selectors in events

for some reason I need to use a variable as the selector for events in backbone, but I can't figure how to do this :
app.views.Selfcare = Backbone.View.extend({
events: {
click window.parent.document .close : "closeWindow"
},
closeWindow: function() {
//code
}
});
I have to use a different scope and I can't do "click .close" : "closeWindow".
Thx for your help.
I had a look at Backbone.js's source code and found out that if your view's events is a function then the function is called and it's return value is used as the events object.
This means that your code can be changed like this:
app.views.Selfcare = Backbone.View.extend({
events: function() {
var _events = {
// all "standard" events can be here if you like
}
_events["events" + "with variables"] = "closeWindow";
return _events;
},
closeWindow: function() {
//code
}
});
THIS is the interesting part of the source code:
if (_.isFunction(events)) events = events.call(this);
Update:
Example is available on JSFiddle HERE**
I'm not sure that you'll be able to use a variable there. You could use the built-in Events methods (see documentation) to add a custom listener, then add an event listener to window.parent.document to trigger that custom event (use the Events.trigger method).
That said, it would be much easier to decouple this event from Backbone entirely (unless you don't want to do that), and go down the addEventListener route:
app.views.Selfcare = Backbone.View.extend({
initialize: function() {
_.bindAll(this, 'render', 'closeWindow');
if(this.options.clickTarget) {
this.options.clickTarget.addEventListener('click', this.closeWindow, false);
}
},
render: function() {
// Render to the DOM here
return this; // as per Backbone conventions
},
closeWindow: function() {
// Stuff here
}
});
// Usage:
var mySelfcare = new app.views.Selfcare({
clickTarget: window.parent.document
});
I think that should work, although I haven't tested it (and there may be one or two syntactical errors!)

Categories