jQuery on event handler losing scope of parent object - javascript

I have an object that has multiple functions being registered to events on page load. This seems to be working fine. However, I am having an issue getting the scope of the object once the event happens. this seems to only pull in the element that is being triggered by the event. I was wondering if anyone could help and tell me where I went wrong?
EDIT 1
I felt that code snippet was pretty concise to the problem. However, I can see where my question may be perceived as lazy.
I have an object that has multiple functions triggered off of events that are dynamically being wired up on load which can be seen here:
var collection = function() {
var _c = {};
_c.el = '#container',
_c.buildItems = function(){
var $el = $('#content2');
var template = Handlebars.compile($("#tpl-collection-item-row").html());
var data = [
{id: 1, val: 'test 1', text: 'this is a test... 1'},
{id: 2, val: 'test 2', text: 'this is a test... 2'},
{id: 3, val: 'test 3', text: 'this is a test... 3'},
];
$el.append(template(data));
},
_c.clickStuff = function() {
alert("hey!");
},
_c.moreClicking = function() {
alert("i knew this would work");
},
_c.events = [
{target: '.row', event: 'click', func: 'clickStuff'},
{target: '#gettingIt', event: 'click', func: 'moreClicking'}
],
_c.initialize = function() {
var _this = this;
$.each(this.events, function(){
var func = _this[this.func]
$(_this.el).on(this.event, this.target, func);
});
},
_c.render = function() {
this.initialize();
this.buildItems();
}
return _c;
}
_c.buildItems is a function that is called to trigger my handlebars template from _c.render(). Prior to this happening I am calling a function to wire up events listed in my _c.events array that take the target object and the type of event happening and mapping to the func name within my object. This is happening in my _c.initialize function.
The events seem to be working perfectly fine. However, I am unsure how to get the scope of my collection function from within functions like _c.clickStuff when they are triggered. I am unsure how to do this and it would be great if someone can explain to me where I went wrong?
Here is a fiddle of my code:
https://jsfiddle.net/0s8vb8m3/3/

You can just reference the _c in your code as it is in the scope of your "collection" function.
var collection = function() {
var _c = {
el: '#container'
};
_c.buildItems = function() {
var $el = $('#content2');
var template = Handlebars.compile($("#tpl-collection-item-row").html());
var data = [{
id: 1,
val: 'test 1',
text: 'this is a test... 1'
}, {
id: 2,
val: 'test 2',
text: 'this is a test... 2'
}, {
id: 3,
val: 'test 3',
text: 'this is a test... 3'
}];
$el.append(template(data));
};
_c.clickStuff = function() {
console.log(_c.el);
};
_c.moreClicking = function() {
alert("i knew this would work");
};
_c.events = [{
target: '.row',
event: 'click',
func: 'clickStuff'
}, {
target: '#gettingIt',
event: 'click',
func: 'moreClicking'
}];
_c.initialize = function() {
$.each(_c.events, function(index, event) {
var func = _c[event.func];
$(_c.el).on(event.event, event.target, func);
});
};
_c.render = function() {
_c.initialize();
_c.buildItems();
};
return _c;
}
var c = collection();
c.initialize();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<div class="row">Blah1</div>
<div class="row">Blah2</div>
<div class="row">Blah3</div>
</div>

Related

React state object attribute is getting set as undefined

I have the following state object initialized called myCriteria
const [myCriteria, setMyCriteria] = useState({
myFieldStatusDropdown: myFieldStatusDropdown,
selectedMyFieldStatus: myVarMyFieldStatusDropdown?.value,
});
Now I have the breakpoint set right above this line
setMyCriteria({
...myCriteria,
selectedMyFieldStatus: myCriteria.myFieldStatusDropdown[0]
});
and at the breakpoint, I inspect and see myCriteria.myFieldStatusDropdown as below
[
{
code: 'Select',
value: 'Select'
}, {
code: 'AA',
value: 'A 1'
}, {
code: 'BB',
value: 'B 1'
}
]
However for some strange reason, after the setMyCriteria line is executed, when I inspect the value of myCriteria.selectedMyFieldStatus, it is wrong
i.e. instead of it being set to
{
code: 'Select',
value: 'Select'
}
it is getting set as undefined
Not sure why it gets set as undefined
I simply initialized using myCriteria and put three objects in it, in form of an array
var myFieldStatusDropdown = [
{
code: 'Select',
value: 'Select'
}, {
code: 'AA',
value: 'A 1'
}, {
code: 'BB',
value: 'B 1'
}
]
const [myCriteria, setMyCriteria] = useState({
myFieldStatusDropdown: myFieldStatusDropdown,
selectedMyFieldStatus: myFieldStatusDropdown[1]
});
then I use setMyCriteria to update the myCriteria
setMyCriteria({
...myCriteria,
selectedMyFieldStatus: myFieldStatusDropdown[0]
},[myCriteria]);

How to get card value after clicking in loop

I have this script for create cards based on list using for loop:
<script>
$(document).ready(function () {
var mokData = [
{ category: "Material", id: '1', name: 'Brakedown of machine' },
{ category: "Material", id: '2', name: 'Brakedown of machine' },
{ category: "Tool", id: '3', name: 'Brakedown of machine' },
{ category: "Tool", id: '4', name: 'Brakedown of line' },
{ category: "Tool", id: '5', name: 'Brakedown of machine' },
{ category: "Tool", id: '6', name: 'Brakedown of line' },
{ category: "Tool", id: '7', name: 'Brakedown of machine' },
{ category: "Tool", id: '8', name: 'Brakedown of line' }
];
$.each(mokData, function (i) {
var templateString = '<article class="card"><h2>' + mokData[i].category + '</h2><p>' + mokData[i].name + '</p><p>' + mokData[i].id + '</p><button id="tes">Start</button></article>';
$('#test12').append(templateString);
})
$("#test12 button").on("click", function () {
alert();
});
});
</script>
Now I need to get the value when the button clicked
In this line:
$('#test12').append(templateString);
JQuery is returning an element which you can directly add an event listener to. You can do something like this:
const element = $('#test12').append(templateString);
const thisData = mokData[i];
$(element).click(function() {
console.log(thisData); //mock data related to the item you've just clicked
});
In the method above, you don't need to attach any additional data to the DOM, you can just reference what you already have access to.
To achieve this you can attach a click handler to all button elements and use the reference to the clicked element, available through the Event object passed to the handler function, to retrieve the content from the HTML related to that button. Try this:
jQuery($ => {
var mokData = [{category:"Material",id:'1',name:'Brakedown of machine'},{category:"Material",id:'2',name:'Brakedown of machine'},{category:"Tool",id:'3',name:'Brakedown of machine'},{category:"Tool",id:'4',name:'Brakedown of line'},{category:"Tool",id:'5',name:'Brakedown of machine'},{category:"Tool",id:'6',name:'Brakedown of line'},{category:"Tool",id:'7',name:'Brakedown of machine'},{category:"Tool",id:'8',name:'Brakedown of line'}]
// create HTML from array of objects
let html = mokData.map(o => `<article class="card"><h2>${o.category}</h2><p>${o.name}</p><p>${o.id}</p><button>Start</button></article>`);
$('#test12').append(html);
// handle button click and retrieve nearest id
$("#test12 button").on("click", e => {
let $btn = $(e.target);
let id = $btn.closest('.card').find('p:eq(1)').text();
console.log(id);
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="test12"></div>
Note that I removed id="tes" from the button in the HTML you create as that will result in repeated id values which is invalid - they must be unique within the DOM.

Getting id or name of folder in fuelux tree

I'm trying to get the id or name of the selected folder in a fuelux tree but couldnt manage to get it done.
My tree is a classic folder/file type tree and I want to be able to see the id of the folder when I click on a file.
this is my datasource for tree
var treeDataSource = new DataSourceTree({
data: [
{ name: 'Elektronik Belgelerim', type: 'folder', 'icon-class': 'blue', additionalParameters: { id: 'F1' } },
{ name: 'Gelen Kutusu', type: 'folder', 'icon-class': 'blue', additionalParameters: { id: 'F2' } },
{ name: 'Giden Kutusu', type: 'folder', 'icon-class': 'blue', additionalParameters: { id: 'F3' } },
{ name: 'Çöp Kutusu', type: 'folder','icon-class':'green', additionalParameters: { id: 'I1' } },
//{ name: 'Çöp Kutusu', type: 'item', 'icon-class': 'success', additionalParameters: { id: 'F4' } },
//{ name: 'Reports', type: 'item', additionalParameters: { id: 'I1' } },
//{ name: 'Finance', type: 'item', additionalParameters: { id: 'I2' } }
],
delay: 400
});
js function for tree begins like this inside tree-custom.js
var e = function (e, i) {
this.$element = t(e), this.options = t.extend({}, t.fn.tree.defaults, i), this.$element.on("click", ".tree-item", t.proxy(function (t) {
this.selectItem(t.currentTarget)
}, this)), this.$element.on("click", ".tree-folder-header", t.proxy(function (t) {
this.selectFolder(t.currentTarget)
}, this)), this.render()
};
and this is where I add the links under folders again inside trree-custom.js. Very primitive I know but that's all I can do with my current skillset. The part I added is between quotes. Rest came with beyondadmin theme and looks like usual fuelux.
selectFolder: function (e) {
//alert("testselectFolder");
//
//alert($('#myTree').tree({ dataSource: dataSource }));
var i, n, r, o = t(e),
s = o.parent(),
a = s.find(".tree-folder-content"),
l = a.eq(0);
//-----------------------------------------------
var li = $('<li>');
var TcgbLink = $('<a href=/E-Belge/Main/Folder/Inbox/?Type=1&DocumentTypeId=3>e-TCGB</div>' +"</br>");
var FaturaLink = $('<a href=/E-Belge/Main/Folder/Inbox/?Type=1&DocumentTypeId=4>e-Fatura</div>' + "</br>");
var Dolasim = $('<a href=>e-Dolasim Belgesi</div>');
li.append(FaturaLink);
a.append(li);
li.append(TcgbLink);
a.append(li);
li.append(Dolasim);
a.append(li);
//-----------------------------------------------
o.find(".fa.fa-folder").length ? (i = "opened", n = ".fa.fa-folder", r = "fa fa-folder-open", l.show(), a.children().length || this.populate(o)) : (i = "closed", n = ".fa.fa-folder-open", r = "fa fa-folder", l.hide(), this.options.cacheItems || l.empty()), s.find(n).eq(0).removeClass("fa fa-folder fa-folder-open").addClass(r), this.$element.trigger(i, o.data())
},
Now these links are being generated under all 4 folders. I want to be able to get the id (or name, preferably Id) of the folder so I can assign new Type parameters to querystring.
So far I tried to reach the id with this.data.id to no avail.
Instead of injecting the folder's children in the selectFolder callback, it is recommended to add the children via the dataSource callback (as in this example code: http://getfuelux.com/javascript.html#tree-usage-javascript).
The first argument to the dataSource is the "parent data" when you click on a tree node (with the second argument being the callback that you send the new array of child data).
This way you can use the selected event for getting your ID, because it gets the jQuery data passed to it.

With knockout.js how to refresh observable array in a Select element

When the dropdown is loaded the items are populated correctly. But when I click the Refresh button the Dropdown items are not refreshed. The data binding isn't working on clicking the Refresh button. After clicking the Refresh button I am expecting to see 'Mary' and 'Sandra'.
Here's the JavaScript:
$(function () {
function viewModel() {
var self = this;
self.persons = ko.observableArray([]);
self.persons.push({
id: 1,
name: 'John'
});
self.persons.push({
id: 2,
name: 'Paul'
});
self.refreshPersonList = function () {
self.persons = ko.observableArray([]);
self.persons.push({ id: 3, name: 'Mary' });
self.persons.push({ id: 4, name: 'Sandra' });
};
}
ko.applyBindings(new viewModel());
});
And HTML:
<select data-bind="options: $root.persons(), optionsValue: 'id', optionsText: 'name'"></select>
<button value="Refresh" data-bind="event: {click : $root.refreshPersonList() }">Refresh Person List</button>
Here you are creating a new array, breaking existing bindings:
self.persons = ko.observableArray([]);
Try emptying the array instead:
self.refreshPersonList = function () {
self.persons.removeAll(); //Empty array
self.persons.push({ id: 3, name: 'Mary' });
self.persons.push({ id: 4, name: 'Sandra' });
};

Classes, Options in Mootools/Prime

I will migrate a project from Mootools to Prime, but now I have a problem with the "setOptions", the function does not work as in Mootools where the options object will merge through supers up the proto chain and contain all the keys.
var A = prime({
options: {
name: 'image',
tag: 'span',
src: '/'
},
constructor: function(options){
this.setOptions(options);
},
getOptions: function(){
console.log(this.options);
}
});
var B = prime({
inherits: A,
options: {
name: 'B'
},
some: function(){
return;
}
});
mixin(A, Options);
mixin(B, Options);
var b = new B({
tag: 'div'
});
b.getOptions(); //the result should be: {name: "B", tag: "div", src: "/"} but is {name: "B", tag: "div"}
Thanks for any idea.
As answered on the mailing list - I even made you a repo - this works out of the box in primish.
https://bitbucket.org/DimitarChristoff/primish-example/src
slightly different syntax (sugar, it's been done to make mootools users happy) but it does also merge options like mootools did:
var A = prime({
options: {
name: 'image',
tag: 'span',
src: '/'
},
implement: [options],
constructor: function(options){
//console.debug(this.options);
this.setOptions(options);
},
getOptions: function(){
console.log(this.options);
}
});
var B = prime({
extend: A,
options: {
name: 'B'
}
});
var C = prime({
extend: B,
options: {
name: 'C'
}
});
var c = new C({
tag: 'div'
});
c.getOptions(); // as expected, all 3 options merged from right to left
Notice distinct lack of the extra mixin() nonsense and the familiar extend term rather than inherits
In prime you'd have to do something like:
var B = prime({
extend: A,
options: Object.merge(A.prototype.options, {
name: 'B'
})
});
where Object.merge is some util - either a prime util or lodash or whatever. in primish that would be prime.merge()

Categories