Javascript function not called on dynamically created button in C# - javascript

I have created button in C# dynamically and added client side event
but that function not getting called instead getting error as:
Uncaught ReferenceError: setPropertyLocation is not defined
Javascript:
function setPropertyLocation() {
alert('Hello');
}
C#:
btnMap.Attributes.Add("type", "button");
btnMap.Attributes.Add("title", "Map");
btnMap.UseSubmitBehavior = false;
btnMap.OnClientClick = "setPropertyLocation();return false";
btnMap.ID = "btnMap" + objPMPropTypestructure.PMFields[fieldcnt].SystemName;
btnMap.CssClass = "dataButton";
btnMap.Text = "G";
btnMap.Enabled = true;
tablecell.Controls.Add(btnMap);

//Try to use this.
document.addEventListener('DOMContentLoaded', function () {
document.getElementById ("btnMap").addEventListener ("click", setPropertyLocation, false);
});

Consider creating this button via JavaScript instead of C#. I assume you are using an update panel. Update panels are a mess. They don't update the DOM elements, they just get rid of the old wrapper and create an entire new, what sets to undefined all JavaScript references to any element in that wrapper.
Well, some times we don't have time to refactor the solution, so we must work with what we have.
You may try add an onclick attribute to the element, just like you did for type and title attribtues.

Related

How to perform button click operation using javascript

I am trying to perform click operation for Buy now button in flipkart through javascript by executing it in chrome console. Using below code
function timeout_trigger() {
var buynowButton = document.getElementsByClassName("_2AkmmA _2Npkh4 _2kuvG8 _7UHT_c")[0];
console.log(buynowButton)
buynowButton.click();
}
setTimeout('timeout_trigger()', 2000);
I am able to see the button element in console log as i printed using
console.log(buynowButton)
But, When click method on buynowButton is not working for that flipkart page
buynowButton.click();
Flipkart don't use click() event for theirs buttons!
It uses Ruby's onClick and some sort of complicated system to prevent auto clicking on their site.
They use function called handleClick, that they give to button as if it was named onClick but really is called o(). And they use special kind of Event to handle it. That's why you cannot use .click(), they blocked it by setting btn.click = ()=>{}. They also used very complicated system to prevent clicking automatically, so basicly you just have to figure out how to bypass that somehow.
dont call the timeout_trigger as a string and pass it as a reference instead.
try :
function timeout_trigger() {
var buynowButton = document.getElementsByClassName("_2AkmmA _2Npkh4 _2kuvG8 _7UHT_c")[0];
console.log(buynowButton)
buynowButton.click();
}
setTimeout(timeout_trigger, 2000);
EDITED
You can use it like this
document.getElementById("btn").addEventListener("click", function(){
console.log('Clicked');
})
var clickBtn = function() {
var buynowButton = document.getElementById('btn');
buynowButton.click();
}
setTimeout(function(){
clickBtn();
}, 1000)
<button id="btn">Click</button>
Removed jQuery and added back.
You can just put the function reference in the setTimeout's first parameter.
var timeout_trigger = function(){
var buynowButton = document.getElementsByClassName("_2AkmmA _2Npkh4 _2kuvG8 _7UHT_c")[0];
console.log(buynowButton)
buynowButton.click();
}
setTimeout(timeout_trigger, 2000);
Triggering a button in jQuery is easy.
$("#id").trigger('click');
or simply
$("#id").click();
Also, don't call your timeout function as a string.
setTimeout(timeout_trigger(), 2000);

If element is not present on page why is JavaScript throwing an error?

My scenario is that I have one JS file which is being used on two HTML pages. One has a button with id="a" and the other doesn't have it. I have attached an event on id="a" by doing this.
document.getElementbyId("a").onclick = function () { .. }
My problem is when I run second file which doesn't have the button with id="a" and it throws the error
TypeError: document.getElementbyId(...) is null
which causes some unexpected behaviour! Is there any way to keep using just one JS file or should I separate the JS file for every html page?
I read a question on StackOverflow here which is about why jQuery doesn't throw an error if the selector is invalid. I need same or similar functionality with vanilla JavaScript.
The simple fix is to add a check:
if (document.getElementById("a") !== null) {
document.getElementById("a").onclick = function () /* .. */ };
}
jQuery will never break on missing elements, it just silently fails. You can argue about whether that is good or not.
The trick jQuery uses is that it will always return something. $("#id") will return a jQuery wrapper. That wrapper has functions like .on and .load and .html. A selector can match one, more or no elements. For the wrapper it doesn't matter how many elements are matched.
It works like this:
var elem = get_element("a");
elem.onclick(callback);
function get_element(id) {
var elem = document.getElementById(id);
return { // return a wrapper
onclick: function (callback) {
if (elem !== null) {
elem.onclick = callback;
} else {
// silently fail
}
}
};
}
Consider testing existance
var elm = document.getElementById("a");
if (elm) elm.onclick = function () { .. };
Or falling back in the case of a falsy
(document.getElementById("a") || {}).onclick = function () { .. };
In this second method, the function still gets set but will be quickly GC'd as the reference to {} dies by the next line.
All of the above solutions are correct. However, you should definitely move away from writing whatever.onclick = function as that is no longer the best way to write your code. Using this method, you only get one click event. Using a more modern approach allows you to attach as many events as you want.
Also, you mention jQuery but there is no jQuery in the supplied code only vanilla JavaScript. Do you need a jQuery solution or JavaScript?
JavaScript
document.addEventListener('DOMContentLoaded', function(){
var elm = document.getElementById('a');
if ( elm ) { //if the element exists add the click event
elm.addEventListener('click', function(){
//Your "onclick" code here
});
}
});
jQuery
$(function(){
$('#a').on('click', function(){
//Your "onclick" code here
});
});

event when adding element into document

Adding new html string into the page:
document.getElementById('container').innerHTML = '<div id="child"></div>';
Is there an event that let me know when child element is in the document?
I have a function, which return some html codeas a string. And when this html will be added in the document, I need to execute javascript function. I've tried to use inline onload event
document.getElementById('container').innerHTML = '<div id="child" onload="console.log(\'ready!\');"></div>';
but it does not seem to work.
UPDATE:
Probably, I should provide more details about the situation. I have a library function
myLibrary.getHtml()
In old version, users just call this function and append the result into the document:
document.getElementById('container').innerHTML = myLibrary.getHtml();
In new version, the result is not a plain html. Now users can interact with it after they append it in the document. So after they append html into the document, I need to go through the result DOM and attach event handlers, hide some elements and other things. That is why, I need to know when they add it in the document and execute a javascript function, which turn plain html into fancy interactive widget.
You could try using DOM Mutation Events, but they are still inconsistently implemented across browsers.
If i have not misunderstood the question, you can probably get this to work
document.getElementById('id').childNodes;
If you can use jQuery, you could write your own custom event which would call the function you need to call whenever the new html has been added:
$('#container').bind('changeHtml', function(e) {
// Execute the function you need
});
And of course instead of just adding the html to the element, you would need to wrap it up in a function which triggers your custom event. Then all you'd need to do is call this function instead of setting the innerHtml yourself.
function addHtml(html) {
$('#container').innerHTML = html;
$('#container').trigger('changeHtml');
}
Solved by myself this way:
myLibrary.getHtml = function() {
var html;
...
var funcName = 'initWidget' + ((Math.random() * 100000) | 0);
var self = this;
window[funcName] = function() { self._initWidget(); };
return html + '<img src="fake-proto://img" onerror="' + funcName + '()"';
}
The idea behind the code is that I specify incorrect url for the src attribute of the img tag and the image triggers error event and call my function. Quite simple :)

How to call touch or click event from a function for an element which was generated dynamically

EDIT:
I've made the changes Matthew and Yossi suggested and it still doesn't seem to work. Those changes I've edited in the post below too.
It now works!
I have a question for a particular problem I can't solve. If you know this question has been answered please send me the link as an answer. I'm trying not to use a framework in this case, but can use jQuery if necessary.
I have found answers on how to attach listeners via functions but I need something so as I wouldn't have to refactor all the code I already have. I'm a freelancer and am working on somebody else's code.
What happens is that I want to detect a touch event for a touch device. This code should work for a PC too so I need to detect clicks. There's this DIV which is created programatically to which I need to add the click or touch, depending on the device. Originally the function was called from an onmousedown event like this:
arrDivAnswers[c].onmousedown = onQuestionDown;
And this is the function it calls:
function onQuestionDown(e)
{
if(!itemSelected)
{
if(this.getAttribute('data-isCorrect') == 'true')
setStyleQCorrect(this, true);
else
setStyleQIncorrect(this);
this.querySelector('.answerText').style.color = '#ffffff';
this.querySelector('.isCorrect').style.visibility = 'visible';
}
itemSelected = true;
}
This was working fine. Now I've made this one which would try and select the correct event for a click or touch (I need a function because I have to use this more than once - and the isTouchDevice is working fine. I use that on some other apps so that code is pretty short and has been tested):
function detectEventClickOrTouch(element, functionToCall){
//detectEventClickOrTouch(arrDivAnswers[c], 'onQuestionDown');
if(isTouchDevice()){
element.addEventListener("touchend", functionToCall, false);
} else{
element.addEventListener("click", functionToCall, false);
}
}
The DIV element gets created like this on some loop:
arrDivAnswers[c] = document.createElement('div');
console.log( "Answer object #" + c + " = " + arrDivAnswers[c] );
arrDivAnswers[c].className = 'autosize';
arrDivAnswers[c].style.textAlign = 'left';
arrDivAnswers[c].setAttribute('data-isCorrect',false);
arrDivAnswers[c].setAttribute('data-isSelected',false);
divAnswerContainer.appendChild(arrDivAnswers[c]);
And then the events get attached to it like this (the older method has been commented out):
for(c;c < arrQuestions[index].arrAnswers.length;c++)
{
var curAnswer = arrQuestions[index].arrAnswers[c];
arrDivAnswers[c].onmouseover = function (e){setStyleQHover(e.currentTarget)};
arrDivAnswers[c].onmouseout = function (e){setStyleQUp(e.currentTarget)};
// Detect touch here *************************
detectEventClickOrTouch(arrDivAnswers[c], onQuestionDown);
//arrDivAnswers[c].onmousedown = onQuestionDown;
// Detect touch here *************************
arrDivAnswers[c].style.visibility = 'visible';
arrDivAnswers[c].querySelector('.answerText').innerHTML = curAnswer.strAnswer;
arrDivAnswers[c].setAttribute('data-isCorrect',curAnswer.isCorrect);
if(curAnswer.isCorrect)
{
//arrDivAnswers[c].classList.add("correctAnswer");
arrDivAnswers[c].className = "correctAnswer";
}
else
{
//arrDivAnswers[c].classList.remove("correctAnswer");
arrDivAnswers[c].className = "autosize";
}
arrDivAnswers[c].setAttribute('data-isSelected',false);
setStyleQUp(arrDivAnswers[c]);
itemSelected = false;
}
[...]
The debugger is throwing this error:
Uncaught TypeError: Object [object DOMWindow] has no method 'getAttribute'
I'm sure I'm messing up the "this" because I'm not calling the function properly.
I agree the "this" variable is getting messed up. The problem is that you are attaching an anonymous function as the callback that then calls eval on another method. This seems unnecessary.
Could you just do this:
function detectEventClickOrTouch(element, functionToCall){
//detectEventClickOrTouch(arrDivAnswers[c], 'onQuestionDown');
if(isTouchDevice()){
element.addEventListener("touchend", functionToCall, false);
} else{
element.addEventListener("click", functionToCall, false);
}
}
And then when you attach the event just do:
detectEventClickOrTouch(arrDivAnswers[c], onQuestionDown);
Since you now call the onQuestionDown function indirectly by the eval the this context seen by the onQuestionDown is the global namespace and not the the element which fired the event.
You don't need the eval anyway... you can pass the function it self
detectEventClickOrTouch(arrDivAnswers[c], onQuestionDown);
and:
element.addEventListener("touchend", functionToCall, false);

Identifying the anchor tag when href is called

How can you identify in a function whether it has been invoked by an anchor tag href?
The event is null in this case, so event.target and event.srcElement won't work.
Code
HTML
Href works here
JavaScript
function SomeFunction ()
{
// I need to get the anchor element that invoked this function
}
What about
Href works here
function SomeFunction(context) {
var callingElement = context;
}
Following what #alex suggested, can you add a script to run in the page load to change the hrefs to be what you want (adding the 'this' reference)?
Take the following script for example, this will change the href value for anchor tags with id set to SomeID or class set to SomeClass:
function changeLinks() {
var all_links = document.getElementsByTagName("a");
for (var i=0; i<all_links.length; i++){
if (all_links[i].id == 'SomeID' || all_links[i].className == 'SomeClass') {
all_links[i].href = 'SomeFunction(this);';
}
}
}
Hope this helps...
Edit:
Following your comment, you can try this:
var clickedAnchor = null;
function setClickedAnchor(obj) {
clickedAnchor = obj;
}
function changeLinks() {
var all_links = document.getElementsByTagName("a");
for (var i=0; i<all_links.length; i++){
if (all_links[i].id == 'SomeID' || all_links[i].className == 'SomeClass') {
all_links[i].href = 'setClickedAnchor(this);' + all_links[i].href;
}
}
}
As far as I know there are only two ways to accomplish this using standard Javascript. The first way has already been outlined -- pass the node as a parameter to the function. The other way would be to handle the onclick event of the anchor. This is very similar to the previous approach in that is requires that you modify the markup to pass a parameter to a function. To do this you'll need to change the markup to the following:
Href works here
function SomeFunction(event) {
var node = event.srcElement;
}
The above code would pass the event object along to the function which would give you all sorts of interesting information about the event.
If you're unable to change the markup that is sent to the browser, you might want to consider using something like JQuery or another AJAX library to search for and modify the event handlers of the nodes at runtime. Modifying the markup before it gets to the browser is obviously preferred, but sometimes you don't have a choice.
Lastly, if you cannot change the markup and don't want to modify the DOM at runtime, you can always see what Javascript engine specific features are available. For example, you might be able to make use of arguments.caller in those engines that support it. I'm not saying that it will work, but you might want to see what's available.

Categories