Same JavaScript for multiple instances of user control not working - javascript

I am using a user control in my website which performs the functionality of auto complete textbox. I have used JavaScript for the keydown and onfocus client events. This is the code:
<script language="JavaScript" type="text/javascript">
function TriggeredKey(e) {
var keycode;
if (window.event) keycode = window.event.keyCode;
if (keycode == 9) {
document.getElementById("<%=pnlSearch.ClientID %>").style.visibility = 'hidden';
document.getElementById("<%=pnlSearch.ClientID %>").style.display = 'none';
}
else {
document.getElementById("<%=hdfkey.ClientID %>").value = keycode;
}
_dopostback();
}
function pasteIntoInput(el) {
var text = document.getElementById("<%=txtSearch.ClientID %>").value;
if (typeof text != "undefined" && text != "") {
el.focus();
el.value = el.value;
if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number") {
var val = el.value;
var selStart = el.selectionStart;
el.value = val.slice(0, selStart) + val.slice(el.selectionEnd);
el.selectionEnd = el.selectionStart = selStart + text.length;
}
else if (typeof document.selection != "undefined") {
el.focus();
}
}
}
When I use a single instance of this control in my aspx page it works fine but when I use more than one instances in my aspx page the JavaScript of all of the controls is overwritten by the last instance of the control in my page and no other control works.

Here's how I've dealt with problems like this in the past...
A block like this goes in an external js file referenced in the control ascx.
function UserControl() {
}
UserControl.prototype = {
DoStuff : function() {
var x = this.clientID;
window.alert(this.pnlSearchClientID);
},
TriggeredKey : function(e) {
var keycode;
if (window.event) keycode = window.event.keyCode;
if (keycode == 9) {
document.getElementById(this.pnlSearchClientID).style.visibility = 'hidden';
document.getElementById(this.pnlSearchClientID).style.display = 'none';
}
_dopostback();
},
pasteIntoInput : function() {
var text = document.getElementById(this.txtSearchClientID).value;
}
};
A block like this goes in the ascx file:
<script type="text/javascript">
function UserControl<%=this.ClientID%>() {
this.pnlSearchClientID = <%=pnlSearch.ClientID%>;
this.txtSearchClientID = <%=txtSearch.ClientID%>;
}
UserControl<%=this.ClientID%> = UserControl.prototype;
</script>
And then in the page including the user control:
<script type="text/javascript">
var inst1 = new UserControl<%=instance.ClientID %>();
inst1.DoStuff();
</script>
The idea is that you have a base class with the functionality you need, shared across all instances of the user control. Then a derived class per instance of the user control, with a new constructor setting properties for all of the instance-specific date (ie the ids of the controls composing the user control). The base class references these properties. The derived class is named using the ClientID of the user control, making it unique on the page.
I don't have access to an asp.net ATM so there are probably errors in here...

First off i would define your javascript functins in one place, perhaps the parent page or even a globally referenced file. That way you dont have the same functions rendered over and over again when you use multiple instances of your user control on a single page.
Then instead of embedding the client IDs of your pnlSearch and txtSearch controls into the JavaScript functions I would recommend passing them into the functions whenever they are called.
The way you have it set up the JavaScript functions on the last instance of your user control that is rendered will be the ones that will be invoked every time, which will cause the functions in the previously rendered user control instances to be ignored.

Related

How to use dynamically created JavaScript object in a conditional statement?

I'm having this little bump in a function, normally if the variable "receivedRDB" is undefined in the DOM, it is dynamically created in a form and if it is defined it takes the value of another variable "receivedR". But "receivedRDB" keeps being created, even when it is already defined in the DOM.
var receivedRDB = document.getElementsByName('receivedR')[0];
if (typeof receivedRDB !== "undefined") {
receivedR = JSON.parse(receivedRDB.value.split(",").slice(0));
} else {
receivedR = [];
}
if (typeof receivedRDB !== "undefined") { //never detected
receivedR.push(toRemoveR);
receivedRDB.value = JSON.stringify(receivedR).replace(/"\[\\|\\"]|\\"/g, "");
} else { //problematic part
event.preventDefault();
receivedR.push(toRemoveR);
var input = document.createElement("input");
input.type = "hidden";
input.name = "receivedR";
input.value = JSON.stringify(receivedR);
rForm.appendChild(input);
}
Here's a solution based on the fact that getElementsByName is a "live" list
Anywhere in your code you can put
var receivedRDB = document.getElementsByName('receivedR');
then change your code to
if (receivedRDB.length !== 0) {
receivedR.push(toRemoveR);
receivedRDB[0].value = JSON.stringify(receivedR).replace(/"\[\\|\\"]|\\"/g, "");
} else {
event.preventDefault();
receivedR.push(toRemoveR);
var input = document.createElement("input");
input.type = "hidden";
input.name = "receivedR";
input.value = JSON.stringify(receivedR);
rForm.appendChild(input);
}
I guess <script> tag which uses receivedRDB appears earlier than the DOM (in <head> for example). If so, there is more than one way to solve.
<script defer>
add an attribute defer to the <script> tag will make the JavaScript code be run after DOM is loaded
window.onload = function(){ /* ... */ }
window.onload will be called after DOM is loaded.
window.addEventListener('load', function(){ /* ... */ })
More compatible one (more than one function can be called individually)
If not the problem please include the minimal code to reproduce the problem.

Trying to write a javascript function inline: doesn't work

I tried to write down this javascript function in an inline way:
function WhichKeyPress(e) {
if (!e) {
//if the browser did not pass the event
//information to the function,
//we will have to obtain it from the
//event register
if (window.event) {
//Internet Explorer
e = window.event;
} else {
//total failure, we have no
//way of referencing the event
return;
}
}
if (typeof (e.keyCode) == 'number') {
//DOM
e = e.keyCode;
} else if (typeof (e.which) == 'number') {
//NS 4 compatible
e = e.which;
} else if (typeof (e.charCode) == 'number') {
//also NS 6+, Mozilla 0.9+
e = e.charCode;
} else {
//total failure, we have no way of obtaining the key code
return;
}
}
It became something like this:
Me.Attributes.Add("onkeydown","var evt; if(!e){ evt = window.event;}else{return;} if(typeof(evt.keyCode == 'number'){//do something}else if....."}
And it so goes on.
Needless to say it doesn't work. I've tried other inline javascript functions like this:
Me.Attributes.Add("onkeydown","if(event.keyCode == 13){return event.keyCode = 9;} ")
It works. But if i do this:
Me.Attributes.Add("onkeydown","var cod = event.keyCode; if(cod == 13){return cod = 9;})
It won't work.
Can i really write a whole javascript function inline? With variables being declared and everything else?
EDIT: I've read the link that #millimoose provided and i'm trying to use an external .js file in my dll in vs2005 but with no success. Here's wha't i've done so far:
1) Created a 'Scripts' folder with the js file in the dll solution.
2) Set the Build Action to 'EmbeddedResource'
3) Overwrote my OnPreRender method like this:
Protected Overrides Sub OnPreRender(ByVal e As EventArgs)
Page.ClientScript.RegisterClientScriptResource(Me.GetType(), "webControlesUES.Scripts.EnterToTab.js")
Page.ClientScript.RegisterStartupScript(Me.GetType(), "EnterToTab", "teste()", True)
End Sub
4) On my Render method, i've added this:
Me.Attributes.Remove("onkeydown")
Me.Attributes.Add("onkeydown", " teste();")
If Me.TextMode = Web.UI.WebControls.TextBoxMode.MultiLine Then
Me.Attributes.Remove("onkeydown")
End If
5) Added this on my AssemblyInfo.vb
<Assembly: System.Web.UI.WebResource("webControlesUES.Scripts.EnterToTab.js", "application/x-javascript")>
6) Built the solution and added the dll for testing.
But it's not working. Am i forgetting something here?
The event object is sent as a parameter to the function also for inline code, but as you don't have any function declaration you need to pick it up from the arguments collection instead of as a named parameter.
Example:
Me.Attributes.Add("onkeydown","var e=arguments[0];if(e.keyCode == 13){ alert('enter'); }");

using a function on textbox focus?

I want to add a autocomplete function to a site and found this guide which uses some js code which works really nice for one textbox: http://www.sks.com.np/article/9/ajax-autocomplete-using-php-mysql.html
However when trying to add multiple autocompletes only the last tetbox will work since it is the last one set.
Here is the function that sets the variables for the js script
function setAutoComplete(field_id, results_id, get_url)
{
// initialize vars
acSearchId = "#" + field_id;
acResultsId = "#" + results_id;
acURL = get_url;
// create the results div
$("#auto").append('<div id="' + results_id + '"></div>');
// register mostly used vars
acSearchField = $(acSearchId);
acResultsDiv = $(acResultsId);
// reposition div
repositionResultsDiv();
// on blur listener
acSearchField.blur(function(){ setTimeout("clearAutoComplete()", 200) });
// on key up listener
acSearchField.keyup(function (e) {
// get keyCode (window.event is for IE)
var keyCode = e.keyCode || window.event.keyCode;
var lastVal = acSearchField.val();
// check an treat up and down arrows
if(updownArrow(keyCode)){
return;
}
// check for an ENTER or ESC
if(keyCode == 13 || keyCode == 27){
clearAutoComplete();
return;
}
// if is text, call with delay
setTimeout(function () {autoComplete(lastVal)}, acDelay);
});
}
For one textbox I can call the function like this
$(function(){
setAutoComplete("field", "fieldSuggest", "/functions/autocomplete.php?part=");
});
However when using multiple textboxes I am unsure how I should go about doing this, here is something I did try but it did not work
$('#f1').focus(function (e) {
setAutoComplete("f1", "fSuggest1", "/functions/autocomplete.php?q1=");
}
$('#f2').focus(function (e) {
setAutoComplete("f2", "fSuggest2", "/functions/autocomplete.php?q2=");
}
Thanks for your help.
You should be using classes to make your function work in more than one element on the same page. Just drop the fixed ID's and do a forEach to target every single element with that class.

Detect if a form is visible or not

I have this scenario, I am detecting all forms on a site: document.forms
And I am trying to detect which forms are visible and which are not visible.
var formElement = []
for (i=0,l=document.forms.length;i<l;i++){
var formIndex = document.forms.item(i);
if (<need here just visible forms>){
formElement.push(formIndex);
}
}
Just to say I am doing this over an other pop up window that is communicating with the browser window with that forms, this depends on jQuery being present on the host site so jQuery is not a solution.
What is the best way to do this.
var isVisible = form.style.display != 'none';
UPDATE #1: hidden attribute
Also the element can be invisible if hidden attribute is specified, so the condition
could be changed to
var isVisible = form.style.display != 'none' && !form.hasAttribute('hidden');
UPDATE #2: jQuery approach:
Find all invisible forms:
$('form:hidden');
or
$('form:not(:visible)');
Find all visible forms:
$('form:visible');
Check is form visible:
$(form).is(':visible');
UPDATE #3: particular case (for original code in question)
It's working pretty well to determine visible forms using a function from my demo:
function isVisible(el) {
return el.style.display != 'none' && !el.hidden;
}
var formElement = [];
for (i=0, l=document.forms.length; i<l; i++) {
var formIndex = document.forms.item(i);
if(isVisible(formIndex)) {
formElement.push(formIndex);
}
}
console.log(formElement);
It's the same loop is this one in demo:
for(var i = document.forms.length; 0 < i--;) {
log('Form #' + i + ': ' + isVisible(document.forms[i]));
}
DEMO
UPDATE #4: pop-up window
I've adapted my example for pop-up window, but I have to say that you're NOT ABLE to deal with elements in document from other host - both pop-up and opener windows should belong to same host.
<script type="text/javascript">
var wnd = window.open('popup.html');
function isVisible(el) {
return el.style.display != 'none' && !el.hidden;
}
wnd.onload = function() {
/* This is working pretty well: */
var formElement = [];
console.log(wnd.document.forms);
for (i=0,l=wnd.document.forms.length;i<l;i++){
var formIndex = wnd.document.forms.item(i);
console.log(formIndex);
if (isVisible(formIndex)){
formElement.push(formIndex);
console.log('Form ' + formIndex.id + ' is visible');
}
}
};
</script>
var forms = document.getElementsByTagName("form");
Then, you can loop through the array and check to see if the tag is visible or not.
You can use this:
$(element).is(":visible") // Checks for display:[none|block], ignores visible:[true|false]
Ref. How do I check if an element is hidden in jQuery?
you can use :
$('#form').is(':visible')
The following will go through all forms and tell which ones are visible and which aren't:
$("form").each(function() {
if ($(this).is(":visible")) {
console.log("Visible: ", this);
} else {
console.log("Hidden: ", this);
}
});
or if you want to get all visible ones at once:
$("form:visible")
And the hidden ones:
$("form:hidden")

Check if browser supports load method on iFrame

I'm trying to code a simple form with file upload which targets the iFrame. I've got it pretty much covered, but Internet Explorer does not support load method on dynamically generated iFrames so I need to do an alternative approach for it. My question is - what's the best and most accurate (plus light) way of identifying the browser type using Javascript?
I know that Modernizr can check for specific methods / properties, but not quite sure if it could help in this specific scenario. It has Modernizr.hasEvent(), but I can't use it to check the dynamically created elements.
The easiest way to check this, to my mind would be:
if ('onload' in iFrameVar)
{
console.log('your code here');
}
Where iFrameVar is a reference to an iframe, of course:
function elemSupportsEvent(elem,e)
{
var f = document.createElement(elem);
if (e in f)
{
console.log(elem + ' supports the '+ e + ' event');
return true;
}
console.log(elem + ' doesn\'t support the '+ e + ' event');
return false;
}
elemSupportsEvent('iframe','onload');//logs "iframe supports the onload event" in chrome and IE8
Just a quick fiddle by means of example of how you can use a function to check event support on various elements.
In response to your comment: if you want to check for dynamic content -as in ajax replies- you could simply use the readystatechange event:
xhr.onreadystatechange = function()
{
if (this.readyState === 4 && this.status === 200)
{
var parent = document.getElementById('targetContainerId');//suppose you're injecting the html here:
parent.innerHTML += this.responseText;//append HTML
onloadCallback.apply(parent,[this]);//call handler, with parent element as context, pass xhr object as argument
}
};
function onloadCallback(xhr)
{
//this === parent, so this.id === 'targetContainerId'
//xhr.responseText === appended HTML, xhr.status === 200 etc...
alert('additional content was loaded in the '+ this.tagName.toLowerCase+'#'+this.id);
//alerts "additional content was loaded in the div/iframe/td/whatever#targetContainerID"
}
if you want to check support for particular event, you can try something like this :
var isEventSupported = (function(){
var TAGNAMES = {
'select':'input','change':'input',
'submit':'form','reset':'form',
'error':'img','load':'img','abort':'img'
}
function isEventSupported(eventName) {
var el = document.createElement(TAGNAMES[eventName] || 'div');
eventName = 'on' + eventName;
var isSupported = (eventName in el);
if (!isSupported) {
el.setAttribute(eventName, 'return;');
isSupported = typeof el[eventName] == 'function';
}
el = null;
return isSupported;
}
return isEventSupported;
})();
here is a live demo for the above :
http://kangax.github.com/iseventsupported/
Use navigator.userAgent. It contains browser user agent
if (navigator.userAgent.search("MSIE 6") == -1){
// We've got IE.
}

Categories