I initially wrote a small ajax-based settings page for an online support system i developed, using jQuery 1.4.2 and it worked fine. However, after upgrading to 1.6.1, additional executions are being called to the functions that were only ever called once previously.
I have three menu options, each with an onclick event to load a specific page into the #settingsph div. Additional code is then called depending on the page in question. (The apache server automatically assumes .php file ext are to be used if none are defined)
function open_page(name) {
$("#settingsph").load("/includes/support/stg/"+name, function(){
if(name == "managecontacts"){
$("#contactselect").load("/includes/support/stg/contactsel");
}else if(name == "changepw"){
$(change_pw(), "changepw_box");
}else if(name == "editcompany"){
$(company_update(), "#company_update");
}
});
}
Once loaded, a select box is presented to users, to select a contact to edit. Onchange, the following function is called.
function open_contact(id) {
$("#contact_info").load("/includes/support/stg/editcontact?id="+id);
if(id != "NewContact") {
$(contact_update(), "#contact_update");
}else{
$(contact_add(), "#contact_add");
}
}
Let's assume the user has decided to edit their contact information (all 3 update pages use roughly the same function, but with the variables changed to reflect the page it took information from).
function contact_update() {
$('input.text-input').css({backgroundColor:"#ffffe0"});
$('input#ldate').live('focus', function(){
$(this).datepick({dateFormat: 'dd/mm/yy'});
});
$("input.text-input").live('focus', function(){
$(this).css({backgroundColor:"#FFFFFF"});
});
$("input.text-input").live('blur', function(){
$(this).css({backgroundColor:"#ffffe0"});
});
$('.error','#contact_info').hide();
$(".buttonupd").live('click', function() {
// validate and process form
// first hide any error messages
$('.error').hide();
var forename = $("input#forename").val();
if (forename == "") {
$("label#forename_error").show();
$("input#forename").focus();
$('input#forename').css({border:"solid #aa0000"});
}else{
$('input#forename').css({border:""});
}
var surname = $("input#surname").val();
if (surname == "") {
$("label#surname_error").show();
$("input#surname").focus();
$('input#surname').css({border:"solid #aa0000"});
}else{
$('input#surname').css({border:""});
}
var phone = $("input#phone").val();
if (phone == "") {
$("label#phone_error").show();
$("input#phone").focus();
$('input#phone').css({border:"solid #aa0000"});
}else{
$('input#phone').css({border:""});
}
var email = $("input#email").val();
if (email == "") {
$("label#email_error").show();
$("input#email").focus();
$('input#email').css({border:"solid #aa0000"});
}else{
$('input#email').css({border:""});
}
if((forename == "") || (surname == "") || (phone == "") || (email == "")){
return false;
}
var contactid = $("input#contactid").val();
var jobtitle = $("input#jobtitle").val();
var site = $("select#site option:selected").val();
var mobile = $("input#mob").val();
var ldate = $("input#ldate").val();
var loginallowed = $("input[name='loginallowed']:checked").val();
var editaddress = $("input[name='editaddress']:checked").val();
var editcontacts = $("input[name='editcontacts']:checked").val();
var editcompany = $("input[name='editcompany']:checked").val();
var lognewissue = $("input[name='lognewissue']:checked").val();
var viewallissues = $("input[name='viewallissues']:checked").val();
var viewchangelog = $("input[name='viewchangelog']:checked").val();
var viewdownloads = $("input[name='viewdownloads']:checked").val();
var newissuenotify = $("input[name='newissuenotify']:checked").val();
var closeissuenotify = $("input[name='closeissuenotify']:checked").val();
var changelognotify = $("input[name='changelognotify']:checked").val();
var viewsitehardware = $("input[name='viewsitehardware']:checked").val();
var viewcompanyhardware = $("input[name='viewcompanyhardware']:checked").val();
var dataString = 'contactid=' + contactid + '&forename=' + forename + '&surname=' + surname + '&jobtitle=' + jobtitle + '&site=' + site + '&email=' + email + '&phone=' + phone + '&mob=' + mobile + '&ldate=' + ldate + '&loginallowed=' + loginallowed + '&editaddress=' + editaddress + '&editcontacts=' + editcontacts + '&editcompany=' + editcompany + '&lognewissue=' + lognewissue + '&viewallissues=' + viewallissues + '&viewsitehardware=' + viewsitehardware + '&viewcompanyhardware=' + viewcompanyhardware + '&viewchangelog=' + viewchangelog + '&viewdownloads=' + viewdownloads + '&newissuenotify=' + newissuenotify + '&closeissuenotify=' + closeissuenotify + '&changelognotify=' + changelognotify;
//alert (dataString);return false;
$.ajax({
type: "POST",
url: "/includes/support/stg/contactupd",
data: dataString,
success: function() {
$('#contact_update').html("<div id='contact_upd_msg'></div>");
$('#contact_upd_msg').html("<h2>Contact Successfully Updated</h2>")
.append("<p>Thank you.</p>")
.hide()
.fadeIn(1500, function() {
$('#contactselect').html("")
$("#contactselect").load("/includes/support/stg/contactsel");
});
}
});
return false;
});
}
The first time the function is executed, it is called only once and appears to be fine. However, if the above function is called a second time to perhaps update another contact, two requests are sent, updating the information twice and refreshing the select box with a list of contacts in twice. If the above function is called a third time, three requests are sent and so on until the page is completely refreshed. I reverted back to 1.4.2 and these functions are only ever executed once, regardless of how many times they're called without a page refresh.
The .live() method was introduced to me here on SO when i first wrote the system and worked well at the time since the .buttonupd does not exist in the DOM when the settings.php page is loaded, is this my problem?
As was mentioned in the comment, you shouldn't be attaching events within a function which could be called multiple times. Each time you call live within that function you are attaching a new event handler. That's why if that method gets called 3 times, triggering the event will cause the handler to run 3 times.
Here is a stripped down example:
http://jsfiddle.net/N78MX/
Notice that every time you click, the number of words added increases by one. This is because each click calls live and attaches another handler.
You can fix this by simply moving all of your live calls outside of your function. Since you are using live it is fine to call it prior to the elements in question being created. So the stripped down example becomes this:
http://jsfiddle.net/N78MX/1
and it works no matter how many times you click. (obviously if this were a real page I would combine those two live calls, but this is just for illustration).
Related
When a user navigates to my site with a qualified URL (e.g. mysite.com/abc.html) I want to call a javascript function first before showing any pages. I need that because my site is driven by ajax.
I have a function that’s called when the page is first loaded:
<body onload="FirstJSFunction(150);”>
That function will intercept the URL and do what I want, but only if the qualified URL is mysite.com/index.html. Any other valid URL within the site will bypass the javascript function and load the requested page. That’s not what I want.
Here is how FirstJSFunction handles it:
<script>
function FirstJSFunction(type) {
var gurl = GetURL();
length = gurl.length;
console.log("SFR URL " + length);
var pos = gurl.lastIndexOf("/");
console.log ("SFR_LastFwdSlash " + pos);
if (length > pos) {
var sub1 = gurl.substr(pos, length);
console.log ("SFR_Sub1 " + sub1);
sub2 = sub1.substr(1, 5);
console.log ("SFR_Sub2 " + sub2);
if (sub2 == "index") {
ShowAjax(3);
return true; }
if (sub2 != "index") {
ShowAjax(3);
return true; }
}
</script>
<script>
function GetURL() {
var loc_href = location.href;
console.log ("URL " + loc_href);
var length = loc_href.length;
console.log ("Length " + length);
var pos = loc_href.lastIndexOf("/");
console.log ("LastFwdSlash " + pos);
var pos2 = loc_href.indexOf("/");
console.log ("FwdSlash " + pos2);
if (length > pos) {
var substr = loc_href.substr(pos, length);
console.log ("Substring " + substr);
return substr; }
}
</script>
So my question is: when the user navigates to my site with any URL other than mysite.com or mysite.com/index.html – for example mysite.com/abc.html – why doesn’t the code above work to intercept the URL and call the javascript function, as happens if the URL is index.html.
Just to clarify, I only want to intercept the first incoming URL. I am not looking to intercept any URL the user enters into the address bar after they have arrived at my site.
Thanks for any help on this.
I'm not sure about everything you explained, so making some assumptions here.
But if that JS code is only on index.html, then it will never run for any other page. For that you would need to include it in every page.
Only the server is able to "see" all the pages accessed by your users.
I'm trying to build a simple tool that will return a Github profile when you search someone's username. Everything seems to be working, except when I search for a different user, the list of followers from the previous user search don't clear.
For example, a user who has seven followers will suddenly have dozens of follower avatars displaying.
Can anyone tell me how to display the correct number of followers unique to each user when fetching different Github profiles?
var response = null;
var followers = null;
document.getElementsByTagName('button')[0].addEventListener('click', function(r) {
getUser(document.getElementsByTagName('input')[0].value);
});
function getUser(name) {
fetch('https://api.github.com/users/' + name)
.then(function(r) {
console.log(r.status);
return r.json();
})
.then(function(j) {
response = j;
assignValues();
getFollowers(j.followers_url);
});
}
function assignValues() {
document.getElementById('loader').style = 'display: none';
document.getElementById('avatar').src = response.avatar_url;
document.getElementById('name').innerText = response.name;
document.getElementById('username').innerText = response.login;
document.getElementById('location').innerText = response.location;
document.getElementById('bio').innerText = response.bio;
document.getElementById('count').innerText = 'Followers: ' + response.followers;
}
function getFollowers(url) {
fetch(url)
.then(function(r) {
return r.json();
})
.then(function(f) {
followers = f;
listFollowers();
});
}
function listFollowers() {
followers.forEach(function(f) {
var li = document.createElement('li');
li.innerHTML = ''+ '<img src="' + f.avatar_url + '" alt="' + f.login + '"/>'+ '';
document.getElementById('list').appendChild(li);
});
}
You need to clear that #list element in listFollowers function before starting appending new followers to it. For example:
var list = document.getElementById('list');
list.innerHTML = '';
followers.forEach(function(f) {
var li = document.createElement('li');
li.innerHTML = ''+ '<img src="' + f.avatar_url + '" alt="' + f.login + '"/>'+ '';
list.appendChild(li);
});
Three sidenotes here:
why do you use global variables response and followers in your rendering functions when you can pass those as arguments?
as you rerender a 'user profile' first, then wait for avatars' fetch, it's still possible for a user to see the followers of user X when looking for user Y. It's better to clear that section (and show some visual cue for loading data) immediately after the user is switched.
as order of fetch responses is not guaranteed, there's a potential race condition here: if user clicks on that button twice (with different inputs), the earlier input might get back later - and overwrite the former. You need to guard against this, either by storing the latest input value and checking the response, or by some other means.
You can test those by artificially throttling the network speed. And believe me, in real world most of your user will have all sorts of problems with that.
Right now I am using a window to view details that are not shown in the grid. I have made my own custom editor in the window as well which hides the details and replaces them with inputs.
Unfortunately I cannot get the Update button to have the same functionality as an update button in the kendo toolbar.
I am using transport and parameter map for my create which works perfectly. I just need to be able to hit the update, which I haven't been able to.
Here is a snippet of code for the template:
<li><b>Change Control Objective</b></li>
<li><textarea type="text" class="k-textbox k-input" data-bind="value:ChangeControlObjective">#= ChangeControlObjective #</textarea></li>
<li><b>Change Control Specifics</b></li>
<li><textarea type="text" class="k-textbox k-input" data-bind="value:ChangeControlSpecifics">#= ChangeControlSpecifics #</textarea></li>
<span class="k-update k-icon k-i-tick"></span>Save
I can't show my JS code but it is based off this dojo: http://dojo.telerik.com/abUHI
UPDATE:
I am able to hit the update in the parametermap off of my save button click but it's sending the old data to the update instead of the new. Here is the button click code:
$("#saveChanges").click(function () {
dataItem.dirty = true;
$("#ccrGrid").data('kendoGrid').saveChanges();
});
Each input has a data-bind attribute and the parametermap looks like this:
case "update":
var changeControlRequestId = options.ChangeControlRequestID;
var changeControlObjective = options.ChangeControlObjective;
var changeControlSpecifics = options.ChangeControlSpecifics;
var productAssociation;
if (options.AccountChangeInfo.ProductAssocation == undefined) {
productAssociation = "";
} else { productAssociation = options.ProductAssocation; }
var amortization;
if (options.AccountChangeInfo.Amortization == undefined) {
amortization = "";
} else { amortization = options.Amortization; }
var productType;
if (options.ProductChangeInfo.ProductType == undefined) {
productType = "";
} else { productType = options.ProductType; }
var productName;
if (options.ProductChangeInfo.ProductName == undefined) {
productName = "";
} else { productName = options.ProductName; }
var productDescription;
if (options.ProductChangeInfo.ProductDescription == undefined) {
productDescription = "";
} else { productDescription = options.ProductDescription; }
var productContract;
if (options.ProductChangeInfo.ProductContractualFeatures == undefined) {
productContract = "";
} else { productContract = options.ProductContractualFeatures; }
var productBehavior;
if (options.ProductChangeInfo.ProductBehavioralAssumptions == undefined) {
productBehavior = "";
} else { productBehavior = options.ProductBehavioralAssumptions; }
var evaluationBehavior;
if (options.ProductChangeInfo.ProductEvaluationBehavior == undefined) {
evaluationBehavior = "";
} else { evaluationBehavior = options.ProductEvaluationBehavior; }
var productStratification;
if (options.ProductChangeInfo.ProductStratificationRoutines == undefined) {
productStratification = "";
} else { productStratification = options.ProductStratificationRoutines; }
if (content.isreadonly == "True") {
alert("you have readonly access");
}
else {
var urlString = "env=" + content.env + "&allyid=" + content.userId + "&changeRequestID" + changeRequestID + "&changeControlObjective=" + changeControlObjective + "&changeControlSpecifics=" + changeControlSpecifics +
"&productAssociation" + productAssociation + "&amortization" + amortization +
"&productType" + productType + "&productName" + productName + "&productDescription" + productDescription +
"&productContract" + productContract + "&productBehavior" + productBehavior + "&evaluationBehavior" + evaluationBehavior +
"&productStratification" + productStratification;
return urlString;
I've been going through this a couple months ago. Per my extensive research there are 2 key sources for doing custom popup editing in Kendo in entire Internet ;) :
Custom editor template
I aslo created a simplified version of this for you here: http://jsbin.com/qudotag/
to cut the elements which can be expanded once you grap the key concepts. Note that this does not work fully as changes are not persisted. It is expected behaviour, as you would need to define the CRUD operations for the grid (what happens when save, cancel etc. is done).
How to deal with CRUD is available in the second source:
Crud with external form
Some heavy studying of these 2 along with going into some more depths of MVVM (which might be intimidating at first, but then really useful for much smoother work with Kendo) will get you going.
Edit: actually you could do with just first approach, which is easier and retain the state by refreshing the grid after cancel.
I have this jzebra applet that I need to do some client side ticket printing.
This is the applets html definition:
<applet id="jzebra" name="jzebra" code="jzebra.PrintApplet.class" archive="../../../../../../web/org.openbravo.howtos/lib/jzebra.jar"
width="10px" height="10px">
The function I call in the form button is this:
function printDocument() {
var applet = document.jzebra;
var frm = document.frmMain;
var url = frm.elements["inpftpOBDir"].value;
var file ="0.txt";
var archivo = url + "/" + file;
if (applet != null) {
var printname = frm.elements["inpPrinterName"].value;
var indice = frm.inpPrinterSelected.selectedIndex;
var printselected = frm.inpPrinterSelected.options[indice].text;
alert(printname);
alert(printselected);
if(printselected == ""){
// printname = "zebra"
//alert('Default : ' + printname);
applet.findPrinter(printname);
monitorFinding();
} else {
//alert('Selected : ' + printselected);
applet.findPrinter(printname);
monitorFinding();
}
alert('File : ' + archivo);
// applet.findPrinter(printname);
applet.appendFile(archivo);
// Send characters/raw commands to printer
applet.print();
alert('The document was sent to the printer.');
}
}
I checked the console and there is a definition of applet, but when it reaches applet.findPrinter(printname), just explodes because applet.findPrinter is not a function.
Has anyone faced this struggle before? I have seen that there is a little gray square in the top left corner of my page. When I hover on it, it displays "undefined".
I finally came up with a very complex solution, having to use jnlp. I will post my code later for references, if anyone else find similar problems.
I do apologize if this is an easy fix, I'm a tad new to jquery. To start I don't think that it is my initial call that is messing up because if I put a simple alert function in than it will work fine onclick, basically when this <li> is clicked on, jquery trigers an ajax to php function sending the class of the <li> to a php script and back, opening an alert with the result. As far as I can tell it should be working, but again my knowledge is rather limited. Any change anyone can take a look at what I have and see if you can clean it up at all, currently nothing happens onclick, no errors even appear in the console. But I imagine that even my ajax call is wrong. Any ideas why nothing happens on click?
HTML:
<li title = "Previous Month" id = "changeMonthBack" class = "<?php echo date('n'); ?>"><img src="images/leftArrow.gif" width="54" height="45" alt="previous month"></li>
jQuery/javascript:
//javascript document
$(document).ready(function(){
//need to do an onclick for getting the new month(previous)
$(".changeMonthBack").click(function(){
function calendar(){
//set the id for php
var identifier = 1;
//get the class to use for month
var str = document.getElementById("changeMonthBack").class;
//get the month number
//if the month is 1, we obviously need it to be 12
if str == 1{
var month = 12;
}
else{
var month = str - 1;
}
$.post("redraw.php"),{
identifier: identifier,
month: month
},
function(data,status){
alert("Data: " + data + "\nStatus: " + status);
};
})//end function 1
});
There are multiple problems with the script.
1. As Aesthete suggested the selector should be an id selector #changeMonthBack
2. You are creating a closure method called calendar but never called it
3. There were multiple syntax error (Use a javascript editor like spket)
You are creating a function called calendar but never calls it.
$(document).ready(function() {
// need to do an onclick for getting the new month(previous)
$("#changeMonthBack").click(function() {
// set the id for php
var identifier = 1;
// get the class to use for month
var str = parseInt($(this).attr('class'),10);
// get the month number
// if the month is 1, we obviously need it to be 12
if (str == 1) {
var month = 12;
} else {
var month = str - 1;
}
$.post("redraw.php", {
identifier : identifier,
month : month
},
function(data, status) {
alert("Data: " + data + "\nStatus: "
+ status);
});
});
});