Access javascript object attribute in dynamically generated handler function - javascript

I have the following Javascript file, where some html is generated dynamically:
(function ($){
NunoEstradaViwer: {
settings: {
total: 0,
format: "",
num: 0;
},
init: function (el, options) {
if (!el.length) { return false; }
this.options = $.extend({}, this.settings, options);
this.itemIndex =0;
this.container = el;
this.total = this.options.total;
this.format = ".svg";
this.num = 0;
this.generateHtml(el);
},
generateHtml: function(container){
var bnext = document.createElement('input');
bnext.setAttribute("type", "button");
bnext.setAttribute("id", "bnext");
bnext.onclick = this.nextImage();
bnext.setAttribute("value", "Next");
container.appendChild(bnext);
},
nextImage: function(){
this.num++;
}
});
What I wanted to do was to access the NunoEstradaViwer attribute num inside the nextImage function but instead the this object points to the bnext button.
Do you know how I can manage that?

check the link
bnext.onclick = this.nextImage; // not bnext.onclick = this.nextImage();
another thing is
NunoEstradaViwer.num++ ; // instead of this.num++

#rahen, I tried your sugestions but unfortunately none worked.
What I found out that worked for me was a solution envolving jquery. I did the following:
generateHtml: function(container){
var bnext = document.createElement('input');
bnext.setAttribute("type", "button");
bnext.setAttribute("id", "bnext");
bnext.setAttribute("value", "Next");
container.appendChild(bnext);
$("#bnext").bind('click',{viewer: this}, function(event) {
event.data.viewer.nextImage();
});
},
nextImage: function(){
this.num++;
}
And this way I can access the value of num and it is changed for the NunoEstradaViwer.

Related

dynamically create element with onclick

I'm obviously missing something, but I haven't been able to find what I am doing wrong and I have been staring at this for entirely too long
function message(options) {
...
options.onclose = options.onclose || null;
...
this.gui = document.createElement('div');
this.msg = document.createElement('div');
...
if (options.onclose != null) {
var close = document.createElement('i');
close.innerHTML = 'close';
close.className = 'material-icons close';
close.onclick = options.onclose;
console.log(close.onclick);
this.msg.append(close);
}
this.msg.innerHTML += options.msg;
this.gui.append(this.msg);
...
return this.gui;
}
msgContainer.append(new message({
class: 'update',
sticky: true,
icon: 'mic',
msg: 'You are in a call',
onclose: () => { console.log('click'); }
}));
from the developer console document.querySelector('.close').onclick is null, but if I add an on click document.querySelector('.close').onclick = () => { console.log('click'); }; it works?
Why it wont work is because on click is a function:
document.querySelector('.close').onclick
doesn't do anything so why call it.
document.querySelector('.close').onclick = () {
alert("did something");
}
so the real question is what do you want to do when clicked? create a new link or div.. look below. I would start using jQuery.
jQuery answer:
$(document).ready(function(){
$(".myclass").click(function(){
$(".container_div").append("<a href='test.php'>test link</a>");
// also .prepend, .html are good too
});
});
Here is working example. I changed your code a little bit. You can add more events by passing it to an array. I used addEventListener.
var msgContainer = document.getElementById('msgContainer');
function message(options) {
options.onclose = options.onclose || null;
this.gui = document.createElement('div');
this.msg = document.createElement('div');
if (options.onclose != null) {
var close = document.createElement('i');
close.innerHTML = 'closepp';
close.className = 'material-icons close';
close.dataset.action = 'close';
this.msg.append(close);
}
this.msg.innerHTML += options.msg;
this.gui.append(this.msg);
// Create listeners dynamically later on
events = [
{ selector: close.dataset.action, eventType: 'click', event: options.onclose }
];
renderElement(this.gui, events);
}
function renderElement(element, events) {
msgContainer.append(element);
for (i = 0; i < events.length; i++) {
var currentEvent = events[i];
var selector = element.querySelector('[data-action="' + currentEvent['selector'] + '"]');
selector.addEventListener(currentEvent['eventType'], currentEvent['event'].bind(this), false);
}
}
new message({
class: 'update',
sticky: true,
icon: 'mic',
msg: 'You are in a call',
onclose: () => { console.log('click'); }
});
<div id="msgContainer">
</div>
I finally figured it out! setting innerHTML makes chrome rebuild the dom and in the process it loses the onclick event, onclick works fine if I use textContent instead of innerHTML. In the below example if you comment out the last line of JS the onclick works, here's the same thing in jsFiddle
var blah = document.getElementById('blah');
var div = document.createElement('button');
div.style['background-color'] = 'black';
div.style.padding = '20px;';
div.style.innerHTML = 'a';
div.onclick = () => { alert('wtf');};
blah.appendChild(div);
// Uncomment this to make onclick stop working
blah.innerHTML += ' this is the culprit';
<div id="blah">
</div>

While creating object and passing in element, getting element is not defined

I am trying to create a js object as below
$(document).ready(function () {
var stickySidebar = {
element: this.element,
topSpacings: 110,
bottomSpacings: $(document).height() - (element.height() + element.offset().top),
getElement: function () {
return this.element;
},
setElement: function (elm) {
element = elm;
},
makeSideBarSticky: function () {
this.element.sticky({
topSpacing: this.topSpacings,
bottomSpacing: this.bottomSpacings,
zIndex: 2
});
}
}
var stickySidebars = Object.create(stickySidebar );
// var stickySidebars = stickySidebar($('#myElement'));
stickySidebars.setElement($('#myElement'));
stickySidebars.makeSideBarSticky();
});
However, I keep on getting element is not defined. I realize element is not defined. However, I am confused as to how I can pass in the element ($('#myElement')) and then call the function makeSideBarSticky. Can someone help me please?
You could create an empty div in your HTML document with id="myElement", and then modify it via JS. This way element is defined for sure
You are assigning a value to the field. Object will not be created because there is an error while creating the object. Assign a value of null instead of this.element.
i dont know what is sticky() is that plugin that you didnt mention you use or something like that , but if we ignored this for a moment , try this :
$(document).ready(function () {
var stickySidebar = {
element: "",
topSpacings: "",
bottomSpacings: "",
getElement: function () {
return element;
},
setElement: function (elm) {
element = elm;
topSpacings= 110;
bottomSpacings= $(document).height() - (element.height() + element.offset().top);
},
makeSideBarSticky: function () {
element.sticky({
topSpacing: topSpacings,
bottomSpacing: bottomSpacings,
zIndex: 2
});
}
}
var stickySidebars = Object.create(stickySidebar );
// var stickySidebars = stickySidebar($('#myElement'));
stickySidebars.setElement($('#myElement'));
stickySidebars.makeSideBarSticky();
});

Split the value of input to array of characters

I want to get the value of the input on click then split the returned value into an array of characters, that what i've already tried :
window.onload = function() {
var textonaut = {
text: '',
letters: []
};
textonaut.text = document.getElementById('textonaut-text').value;
var go = document.getElementById('go-button');
go.addEventListener('click', function(e) {
e.preventDefault();
textonaut.letters = textonaut.text.split('');
for(var i = 0; i < textonaut.letters.length; i++) {
console.log(textonaut.letters[i]);
};
});
}
<input id="textonaut-text" type="text"><button id="go-button">go</button>
I can't figure out why this doesn't work.
Put textonaut.text = document.getElementById('textonaut-text').value; inside your addEventListener callback. Then it should work.
window.onload = function() {
var textonaut = {
text: '',
letters: []
};
var go = document.getElementById('go-button');
go.addEventListener('click', function(e) {
e.preventDefault();
textonaut.text = document.getElementById('textonaut-text').value;
textonaut.letters = textonaut.text.split('');
for(var i = 0; i < textonaut.letters.length; i++) {
console.log(textonaut.letters[i]);
};
});
}
<input id="textonaut-text" type="text"><button id="go-button">go</button>
If you set the value of textonaut.text outside the callback, it will remain as '' no matter what happens (this value is set when the JS file loads).
The callback function of the addEventListener is triggered at every click on the button. It means that at every click, the value textonaut.text is set at everything's inside your input.
Read addEventListener documentation for more information.
You should get the input value after the click not before, so put the line :
textonaut.text = document.getElementById('textonaut-text').value;
Inside the callback.
NOTE : As written now in your OP the document.getElementById('textonaut-text').value will always return an empty string "".
window.onload = function() {
var textonaut = {
text: '',
letters: []
};
var go = document.getElementById('go-button');
go.addEventListener('click', function(e) {
e.preventDefault();
textonaut.text = document.getElementById('textonaut-text').value;
textonaut.letters = textonaut.text.split('');
for(var i = 0; i < textonaut.letters.length; i++) {
console.log(textonaut.letters[i]);
};
});
}
<input id="textonaut-text" type="text"><button id="go-button">go</button>

If value is empty don't add class attr upon append

http://jsbin.com/guvixara/1/edit
I'm dynamically adding a button...
$(".confirm-add-button").on("click", function() {
var $ctrl = $('<button/>').attr({ class: $('.newbtnclassname').val()}).html($('.newbtntxt').val());
$(".drawing-area").append($ctrl);
UpdateView();
});
However I don't (as in do NOT) want to add the class attribute if the $('.newbtnclassname').val() is blank.
If anyone can help with this it'll be greatly appreciated.
You'd do that like this
$(".confirm-add-button").on("click", function() {
var klass = $('.newbtnclassname').val(),
text = $('.newbtntxt').val(),
obj = {};
if (klass) obj['class'] = klass;
if (text) obj['text'] = text;
$(".drawing-area").append( $('<button />', obj) );
UpdateView();
});
JSBIN
Add this:
$(".confirm-add-button").on("click", function() {
var $ctrl = $('<button/>').attr({ class: $('.newbtnclassname').val()}).html($('.newbtntxt').val());
if($('.newbtnclassname').val() != ""){//add this if statement
$(".drawing-area").append($ctrl);
}
UpdateView();
});
here is the link
You can do that with a simple if condition:
$(".confirm-add-button").on("click", function() {
var $ctrl = $('<button/>').html($('.newbtntxt').val());
var cssClass = $('.newbtnclassname').val();
if (cssClass != "") {
$ctrl.addClass(cssClass);
}
$(".drawing-area").append($ctrl);
UpdateView();
});

Create a jQuery special event for content changed

I'm trying to create a jQuery special event that triggers when the content that is bound, changes. My method is checking the content with a setInterval and check if the content has changed from last time. If you have any better method of doing that, let me know. Another problem is that I can't seem to clear the interval. Anyway, what I need is the best way to check for content changes with the event.special.
(function(){
var interval;
jQuery.event.special.contentchange = {
setup: function(data, namespaces) {
var $this = $(this);
var $originalContent = $this.text();
interval = setInterval(function(){
if($originalContent != $this.text()) {
console.log('content changed');
$originalContent = $this.text();
jQuery.event.special.contentchange.handler();
}
},500);
},
teardown: function(namespaces){
clearInterval(interval);
},
handler: function(namespaces) {
jQuery.event.handle.apply(this, arguments)
}
};
})();
And bind it like this:
$('#container').bind('contentchange', function() {
console.log('contentchange triggered');
});
I get the console.log 'content changed', but not the console.log 'contentchange triggered'. So it's obvious that the callback is never triggered.
I just use Firebug to change the content and to trigger the event, to test it out.
Update
I don't think I made this clear enough, my code doesn't actually work. I'm looking for what I'm doing wrong.
Here is the finished code for anyone interested
(function(){
var interval;
jQuery.event.special.contentchange = {
setup: function(){
var self = this,
$this = $(this),
$originalContent = $this.text();
interval = setInterval(function(){
if($originalContent != $this.text()) {
$originalContent = $this.text();
jQuery.event.handle.call(self, {type:'contentchange'});
}
},100);
},
teardown: function(){
clearInterval(interval);
}
};
})();
Thanks to Mushex for helping me out.
also take a look to James similar script (declaring as jquery object method and not as event)
jQuery.fn.watch = function( id, fn ) {
return this.each(function(){
var self = this;
var oldVal = self[id];
$(self).data(
'watch_timer',
setInterval(function(){
if (self[id] !== oldVal) {
fn.call(self, id, oldVal, self[id]);
oldVal = self[id];
}
}, 100)
);
});
return self;
};
jQuery.fn.unwatch = function( id ) {
return this.each(function(){
clearInterval( $(this).data('watch_timer') );
});
};
and creating special event
jQuery.fn.valuechange = function(fn) {
return this.bind('valuechange', fn);
};
jQuery.event.special.valuechange = {
setup: function() {
jQuery(this).watch('value', function(){
jQuery.event.handle.call(this, {type:'valuechange'});
});
},
teardown: function() {
jQuery(this).unwatch('value');
}
};
Anyway, if you need it only as event, you script is nice :)
I know this post/question is a little old, but these days I was behind a similar solution and I found this:
$('#selector').bind('DOMNodeInserted', function(e) {
console.log(e.target);
});
Source: http://naspinski.net/post/Monitoring-a-DOM-Element-for-Modification-with-jQuery.aspx
Hope this help someone!
The finished code in the original question worked for me, thank you! I would just like to note that I am using jquery 1.9.1 and $.event.handle seems to have been removed. I changed the following to get it to work.
jQuery.event.handle.call(self, {type:'contentchange'});
to
jQuery.event.dispatch.call(self, {type:'contentchange'});
maybe you could try Mutation Observer
Here are the code:
mainArea = document.querySelector("#main_area");
MutationObserver = window.MutationObserver;
DocumentObserver = new MutationObserver(function() {
//what you want to run
});
DocumentObserverConfig = {attributes: true, childList: true, characterData: true, subtree: true};
DocumentObserver.observe(mainArea, DocumentObserverConfig);

Categories

Resources