Problem with javascript onclick function string - javascript

Hey all, i have been trying for a few minutes on this problem and i can not seem to figure out how to correct it. I tend to have the hardest time doing stuff like this when it involves more than one varable within the function.
Here is the code:
var tempString = "thePrompt('Are you sure you wish to delete this?', 'theDel('" + IDnum + "', '" + theTitle + "', \'" + temperDay + "\', \'" + temperMonth + "\', \'" + temperYear + "\', \'" + DDiff + "\')";
html +=
"<div id='theTable" + IDnum + "' class='fc-event fc-event-hori fc-corner-left fc-corner-right' style='position:absolute; margin-top: 15px; z-index:8;left:"+left+"px'><div id='apDEL' style='position:relative;width:0px;height:0px;z-index:1000; top:-13px; left:2px; float:left;'><img src='img/xCal.png' width='15' height='15' alt='' border='0' onclick=\"" + tempString + "\" /></div>" + (ETC ETC...)
The error i keep getting is this:
Error: missing ) after argument list
Line: 1, Column: 68
Source Code:
thePrompt('Are you sure you wish to delete this posting?', 'theDel('105', '50 points for visiting us today!!!!', '13', '3', '2010', '2')
And its pointing to the '105'.
As always, any help would be wonderful! :o)
David
EDIT/UPDATE
Ok, so now i have moved some things around and i got it working (that is sending the values to the popup prompt box BUT for some reason it doesn't see my function after i hit the delete button! This is because the prompt is on the main page and the code i am working with is inside a iframe.
function theDel(theID, theTitle, day, month, year, DDiff)
{
var tempString = "delClientE(" + theID + ", '" + theTitle + "', " + day + ", " + month + ", " + year + ", " + DDiff + ")";
parent.thePrompt('Are you sure you wish to delete this event?', tempString);
}
The delete button values now look like this:
delClientE(110, 'sadfsadfsdf', 14, 3, 2010, 2); jQuery.prompt.close();
However, even putting parent.delClientE doesnt find the function either... How can i call it from within the iframe when the prompt box is outside of that?
David

Keeping track of escaping in nested contexts is really hard, and because when you get it wrong you've very often given yourself a script-injection security problem, it's much better to avoid creating HTML/JS by sticking strings together.
Instead, use DOM methods to assign your event handler from JavaScript and say goodbye to all that irritating backslash and quoting stuff:
var img= document.createElement('img');
img.src= 'img/xCal.png';
img.width=img.height= 15;
img.onclick= function() {
if (confirm('Are you sure you wish to delete this?'))
theDel(IDnum, theTitle, temperDay, temperMonth, temperYear, DDiff);
};
div.appendChild(img);

it's because of the quotes here 'theDel('" + you should escape the inner single quotes.
Edit. that is of course, in addition of the missing right paren issue already on the table. :)

I think it's missing at the end of the statement .. your statement looks like this:
var tempString = "thePrompt('question', theDel(params)";
.. where it should have one more closing ')' at the end.
and one more thing you might want to look at is the fact that the arguments in theDel are wrapped in single quotes.
thePrompt('Are you sure you wish to delete this?', 'theDel('105', '50 points for visiting us today!!!!', '13', '3', '2010', '2')' )
And that might be a problem since the params in thePrompt are also wrapped in single quotes so I would make the thePrompt have double quotes arround it's params so it would look something like this:
var tempString = "thePrompt(\"Are you sure you wish to delete this?\", \"theDel(\'" + IDnum + "\', \'" + theTitle + "\', \'" + temperDay + "\', \'" + temperMonth + "\', \'" + temperYear + "\', \'" + DDiff + "\')\")";

David, not sure if this has been answered to your satisfaction yet, but it might be easier to create a temporary variable for this:
var theDel = "theDel('" + IDnum + "', '" + theTitle + "', '" + temperDay + "', '" + temperMonth + "', '" + temperYear + "', '" + DDiff + "')";
var tempString = "thePrompt('Are you sure you wish to delete this?', \' + theDel + \')";

First of all, you'd be far better using event delegation with the js library of your choice.
Failing that, a string interpolation function makes these sorts of things easier:
String.prototype.format = function(values) {
return this.replace(/\{(.+?)\}/g, function(s, key) {
return values[key];
});
}
So long things like this become:
var s = 'blah blah blah "{IDnum}" blah blah blah \'{foosball}\''.format({ IDnum: '1', foosball: 'xyz'});
(If you don't like manipulating String's prototype, you can put the function somewhere else.)

Ok, how about this?
iFrame source
<html>
<head>
<script type="text/javascript">
function localDel(params){
if (window.parent && typeof window.parent.thePrompt==='function')
window.parent.thePrompt('Are you sure you wish to delete this event?', params);
}
</script>
</head>
<body>
<p onclick="localDel([1,'some title', 14, 3, 2010, 2])">delete</p>
<p onclick="localDel([2,'another title', 14, 3, 2010, 2])">delete</p>
</body>
</html>
Parent source
<html>
<head>
<script type="text/javascript">
function thePrompt(msg,params) {
if(confirm(msg)) theDel.apply(this,params);
}
function theDel(id, title, tDay, tMonth, tYear, dDiff) {
alert(id);
// etc...
}
</script>
</head>
<body>
<iframe src="iframe.html" />
</body>
</html>

I finally got it!! YAY! :o)
function theDel(theID, theTitle, day, month, year, DDiff)
{
var tempString = "window.frames.theCal.delClientE(" + theID + ", '" + theTitle + "', " + day + ", " + month + ", " + year + ", " + DDiff + ")";
parent.thePrompt('Are you sure you wish to delete this event?', tempString);
}
I needed the window.frames.theCal in order to call my function. theCal is my iframe id.
David

Related

Can only display information about the last created object | Overwrites previous

I have a system where I can create some "houses" and "people". The next step for me, is that I want to display some information about the house that I click on. However, I can only access the information about the last of the houses that is created, not mather on what house I click.
See the image here:
The house on the right is the last house that I've created. The informations displays correct. But if I click the first house (the one on the left), my information won't change.
I have created a JSFIDDLE here where our can try it our for yourself.
I'm guessing that my problem lies somewhere in my objHouse.click(function(). I've tried several different ways. Right now I'm trying to target it like this:
$('#BtnCreateHouse').click(function(){
oHouse = CreateHouseInMemory();
CreateHouseInLayout(oHouse);
});
function CreateHouseInMemory()
{
var oHouse =
{
"id": "H"+GetRandomNumber(999, 999999999999),
"StreetMame": $('#StreetName').val(),
"Number": $('#Number').val(),
"MaxPeople" : $('#MaxPeople select').val(),
"aPeople": []
}
aHouses.push(oHouse);
console.log(oHouse);
return oHouse;
}
function CreateHouseInLayout()
// See JSFIDDLE, to much code to be posted here.
var objHouse = $('#' + oHouse.id)
objHouse.click(function(){
$("#WindowDisplayHouseInfo").show();
$('#ShowId').text("ID: " + oHouse.id);
$('#ShowStreetName').text("Street Name: " + oHouse.StreetMame);
$('#ShowNumber').text("Number: " + oHouse.Number);
$('#ShowMaxInhabitants').text("Max inhabitants: " + oHouse.MaxPeople);
for(var i = 0; i < oHouse.aPeople.length; i++)
{
$('#ShowInhabitants').html("<br />" + "Inhabitant: " + oHouse.aPeople.length
+"<br />" + "ID: " + oHouse.aPeople[i].id
+"<br />" + "Name: " + oHouse.aPeople[i].Name
+"<br />" + "Last Name: " + oHouse.aPeople[i].Lastname
+"<br />" + "Age: " + oHouse.aPeople[i].Age
+"<br />" + "Gender: " + oHouse.aPeople[i].sGender
);
}
$('.DeleteHouse').click(function()
{
$(objHouse).children().each(function(){
$(this).appendTo($('#City')).css({"top":"" , "left":""});
});
$(objHouse).remove();
$("#WindowDisplayHouseInfo").hide();
});
});
I really hope that one of you can tell me what it is that I'm doing wrong. I've been stuck for hours now.
UPDATE
I've found out that if I change:
objHouse.click(function(){
to
$('.House').click(function(){
and then change
$('#ShowId').text("ID: " + oHouse.id)
to
$('#ShowId').text("ID: " + this.id);
Then it will work for the ID, but if I fx. write ("Street Name: " + this.StreetName); then it won't work. Any idea why?
Updated JSFIDDLE here: http://jsfiddle.net/Adnaves/pcVR6/2/
Inside:
$('#BtnCreateHouse').click(function(){
oHouse = CreateHouseInMemory();
CreateHouseInLayout(oHouse);
});
You don't define the oHouse var in the function scope and later in the CreateHouseInLayout function you don't use the passed parameter but the global variable from before. So the click function creates a oHouse variable in the global symbol table, which is later accessible by the CreateHourseInLayout and this works fine the first time, but the second time you click you're overwriting the global variable and the first house == the second house. What you need to do is properly scope your variables:
$('#BtnCreateHouse').click(function(){
var oHouse = CreateHouseInMemory(); // Create the house var locally and pass it to the other function
CreateHouseInLayout(oHouse);
});
function CreateHouseInMemory() {
var oHouse = {
"id": "H"+GetRandomNumber(999, 999999999999),
"StreetMame": $('#StreetName').val(),
"Number": $('#Number').val(),
"MaxPeople" : $('#MaxPeople select').val(),
"aPeople": []
};
aHouses.push(oHouse);
console.log(oHouse);
return oHouse;
}
function CreateHouseInLayout(oHouse) { // use the passed house object
var objHouse = $('#' + oHouse.id)
objHouse.click(function(){
$("#WindowDisplayHouseInfo").show();
$('#ShowId').text("ID: " + oHouse.id);
$('#ShowStreetName').text("Street Name: " + oHouse.StreetMame);
$('#ShowNumber').text("Number: " + oHouse.Number);
$('#ShowMaxInhabitants').text("Max inhabitants: " + oHouse.MaxPeople);
for(var i = 0; i < oHouse.aPeople.length; i++) {
$('#ShowInhabitants').html("<br />" + "Inhabitant: " + oHouse.aPeople.length
+"<br />" + "ID: " + oHouse.aPeople[i].id
+"<br />" + "Name: " + oHouse.aPeople[i].Name
+"<br />" + "Last Name: " + oHouse.aPeople[i].Lastname
+"<br />" + "Age: " + oHouse.aPeople[i].Age
+"<br />" + "Gender: " + oHouse.aPeople[i].sGender
);
}
$('.DeleteHouse').click(function() {
$(objHouse).children().each(function(){
$(this).appendTo($('#City')).css({"top":"" , "left":""});
});
$(objHouse).remove();
$("#WindowDisplayHouseInfo").hide();
});
});
}
Keep in mind that withing the CreateHouseInLayout method now the oHouse variable is local and all functions created within that one can access it. So your objHouse.click(function(){}) also has access to that local copy and will display the correct information. Where objHouse is a single element that represents that specific house. If you use the $('.House').click() like you do in the JSFIDDLE example, you're binding the callback to all elements, but with a single oHouse object, so they will all display the same info (i.e. use the objHouse method).

attempting to split string dynamically keep getting error?

I'm attempting to split a string I'm passing into
$("#groupUL").append("<li>" + "<h2>About Item:</h2> " + response.data[i].message + "<br /> " + "<h2>Posted By:</h2> <a href='#' onclick='splitName('" + response.data[i].from.name + "');'>" + response.data[i].from.name + "</a>" + "<br />");
Seems to be passing me the error
SyntaxError: syntax error
splitName(
Not sure how that's wrong...Here is the splitname function if that helps
function splitName(txt){
var myString = txt;
var mySplitResult = myString.split(" ");
console.log("The first element is " + mySplitResult[0]);
console.log("<br /> The second element is " + mySplitResult[1]);
console.log("<br /> The third element is " + mySplitResult[2]);
};
It's too hard to get it right when you put quotes in quotes in quotes and you try to escape it right. You got it wrong.
A solution is to make it in small parts :
var action = "splitName('" + response.data[i].from.name + "');";
$("#groupUL").append("<li>" + "<h2>About ... onclick=\""+action+"\">...");
But the best solution would be to follow best practice, that is not inline the javascript but use jQuery's binding function :
$("#groupUL").append("... <a id=myid ...");
$("#myid").click(function(){ splitName(response.data[i].from.name) });
I think the only problem with your code is with your readability issue. So I would suggest please improve it. Lets have a look at it. My code example # JSbin.
Here is the code :- (which i think is better)
var response = {
data : {
message: 'Cleaning code',
from: {
name: 'Clean Code works'
}
}
};
var li = $('<li>'); //Create empty li (Not Appending to DOM now due to performance issues)
$('<h2>').html('About Item:' + response.data.message + '<br />').appendTo(li);
$('<h2>').html('Posted By:').appendTo(li);
$('<a>').attr('href', '#')
.html(response.data.from.name)
.appendTo(li)
.click(function() {
splitName(response.data.from.name);
});
$('<br>').appendTo(li);
// Append li to ul (Final operation to DOM)
li.appendTo('#groupUL');
function splitName(txt){
var myString = txt;
var mySplitResult = myString.split(" ");
console.log("The first element is " + mySplitResult[0]);
console.log("The second element is " + mySplitResult[1]);
console.log("The third element is " + mySplitResult[2]);
}

Workflow using Google Apps Script - I need to email the user in my first step

I'm creating a workflow process that will email a body of a form to users in that workflow. I can iterate through the users and send an email but I do not now how to pass the "e" parameters for the body of the email. I actually already have a function that will send the body , but I need to include this in my step process (I think).
Hear is my code that will send email
function sendEmail_(e) {
var sheet = SpreadsheetApp.openById("0AuCblud0Ss7sdfA1bXZjYXA0Y0IhthkhUQm5vWG02MVE").getActiveSheet();
var row = sheet.getLastRow()+1;
sheet.getRange(row,3).setValue(row);
var range = sheet.getRange(sheet.getLastRow(),1,1,23);
range.setValues([[e.parameter.LastName,e.parameter.FirstName,row /*e.parameter.DivisionName*/,e.parameter.EffectiveDate,e.parameter.Status,
e.parameter.Network,e.parameter.EmployeeNewPosition,e.parameter.DivisionFolder,e.parameter.SpecificIndividual,
e.parameter.Email,e.parameter.username,e.parameter.who,e.parameter.Banner,e.parameter.RMS ,e.parameter.HAPPY,e.parameter.Sweeps,
e.parameter.Comcate,e.parameter.Netviewer,e.parameter.NetDispatcher,e.parameter.IMARS,"pending", e.parameter.DivHeadEmail, e.parameter.Director]]);
var body = '<form action= <form action = " https://sites.google.com/a/macros/wichitafallstx.gov/s/AKfycbxAOGO6q9ofauf34xlDA9sLG8sUXeZsuvQkDKATOQ/exec" method ="post">' +
"<b>Last Name:</b>" + e.parameter.LastName + '<br><br>' +
"<b>First Name:</b>" + e.parameter.FirstName + '<br><br>' +
"<b>Division Name:</b>" + e.parameter.DivisionName + '<br><br>' +
"<b>Effective Date:</b>" + e.parameter.EffectiveDate + '<br><br>' +
"<b>Employee Status:</b>" + e.parameter.Status + '<br><br>' +
"<b>Network:</b>" + e.parameter.Network + '<br><br>' +
"<b>Employee New Position:</b>" + e.parameter.EmployeeNewPosition + '<br><br>' +
"<b>Division Folder:</b>" + e.parameter.DivisionFolder + '<br><br>' +
"<b>Specific Individual:</b>" + e.parameter.SpecificIndividual + '<br><br>' +
"<b>Email:</b>" + e.parameter.Email + '<br><br>' +
"<b>Username:</b>" + e.parameter.username + '<br><br>' +
"<b>who:</b>" + e.parameter.who + '<br><br>' +
"<b>Banner:</b>" + e.parameter.Banner + '<br><br>' +
"<b>RMS:</b>" + e.parameter.RMS + '<br><br>' +
"<b>HAPPY:</b>" + e.parameter.HAPPY + '<br><br>' +
"<b>Sweeps:</b>" + e.parameter.Sweeps + '<br><br>' +
"<b>Comcate:</b>" + e.parameter.Comcate + '<br><br>' +
"<b>Netviewer:</b>" + e.parameter.Netviewer + '<br><br>' +
"<b>NetDispatcher:</b>" + e.parameter.NetDispatcher + '<br><br>' +
"<b>IMARS:</b>" + e.parameter.IMARS +
'<br />' +
'<br />' +
'<input type="hidden" name="row" value=" ' + row +' "/>' +
'<input type="submit" value="Approve" onclick="approve()" />' +
'</form>'
;
// var owners = e.parameter.DivHeadEmail;
// var mail = MailApp.sendEmail(owners, "test",'' , {htmlBody:body});
}
I need to email the html body from the code above with the step in the work flow in this "createStep" function. I dont know how to reference the variable "body" from the code above to this function or even if I could include the html body in this function. How would I do this?
function createStep(approvers) {
var step = new Object();//javascript object
step['numberOfApprovers'] = approvers.length; //set number of approvers passed in array
step['approvers'] = approvers.slice(0); //slice copies array
step['status'] = 'pending'; //set statust to pedning
for (var i in approvers)
step[approvers[i]] = 'pending'; //iterate field that indicates specific status
for (var m in approvers)
step[approvers[m]] = MailApp.sendEmail(approvers, "test", "test",{htmlBody:body});
return step
}
If you want to include the body variable in both functions, declare the variable outside the functions:
var body;
function sendEmail_(e) {
...
body = ...
}
function createStep(approvers) {
...
sendEmail(..., {htmlBody:body}
..
}
However, I don't think you can send POST parameters to a script, GET should work. But I haven't tried it myself.
On second thought, and trying to understand the process, why not create a web app that just displays the info on the screen, with an Approve button under it, and send a link to that app to each approver?
Advantage is that you can give access to the script to logged in users only, and check that the right person is approving--makes it more safe.
Note that you can use the ObjDB library to easily retrieve a row from a spreadsheet:
http://www.harryonline.net/scripts/objdb-storing-data-with-google-apps-script/482
I would create a spreadsheet with two worksheets. The first contains the data, the second contains the list of approvers. One column in the first sheet indicates the last approver.
So your script checks the rows in the data worksheet, and sends an email containing the data of a row that has not been approved yet. It includes a link to approve. The receiver checks the data, and clicks on the link to approve.
This brings him to a script, where he has to log in. The script checks the user with the expected approver, and if OK, increases the value in the approver column in the data sheet. While there are more approvers, continue the loop.

Are there any string formatting functions built into jQuery?

I have the following code:
$("#stats-list")
.append("<li>Elapsed: " + ajaxElapsed + "</li>\n" +
"<li>Display: " + tableElapsed + "</li>\n" +
"<li>Total: " + (ajaxElapsed + tableElapsed) + "</li>");
This was originally three appends that I concatenated into one. Is there anything I could do with jQuery that would clean up this code even more. What I was wondering was if jQuery has any string formatting with tokens that I could use.
function format(formatString) {
var args = Array.prototype.slice.call(arguments,1);
return formatString.replace(/\{(\d+)\}/g, function(match, num) {
return args[Number(num)];
});
}
format("<li>Elapsed: {0}</li>\n<li>Display: {1}</li>\n<li>Total: {2}</li>",
ajaxElapsed, tableElapsed, ajaxElapsed + tableElapsed);
afaik there is none built-in, but a powerful templating-subsystem, see jQuery Templates
just for completeness, i think this could be done more elegant:
var list = $('#stats-list');
$('<li />').text('Elapsed: ' + ajaxElapsed).appendTo(list);
$('<li />').text('Display: ' + tableElapsed).appendTo(list);
$('<li />').text('Total: ' + (ajaxElapsed + tableElapsed)).appendTo(list);
If you have many items you can do something like this to avoid missing + and writing li so many times. You can add any number of items inside the array and they will be joined with lis appropriately.
var list = '<li>' + [
'Elapsed: ' + ajaxElapsed,
'Display: ' + tableElapsed,
'Total: ' + ajaxElapsed + tableElapsed
].join('</li><li>') + '</li>';
$("#stats-list").append(list);
As a note I wouldn't use \n. li is a block element by default, so you'd be better styling it with css.

How to append free text elements from array to DOM

I'm trying to append information to my page from two different JavaScript arrays. It looks like this.
var i = 0;
var videoArr=["big long array"];
var descriptArr=["big long array"];
function appendVideo(i) {
var url = "http://i.ytimg.com/vi/" + videoArr[i] + "/mqdefault.jpg";
$("#history").append("<img src=\"" + url + "\" width=\"120\" height=\"68\" />**NEED TO PRINT descriptArr[i] HERE**<br />");
}
function loadHistory() {
while (i < '.$length.') {
appendVideo(i);
i = i + 1;
}
}
So the above code is appending all the elements from the videoArr no problem. The problem is the descriptArr is full of free text descriptions that I need to print beside each videoArr element. What's he best way to do this? I presume it's not document.write(descriptArr[i])...
Try this, as long as you are sure that descriptArr does not contain any HTML literals.
$("#history").append("<img src=\"" + url + "\" width=\"120\" height=\"68\" />" + descriptArr[i] + "<br />");
Not the best way, but just try something like this
$("#history").append("<img src=\"" + url + "\" width=\"120\" height=\"68\" />" + descriptArr[i] + "<br />");
Ive used this for achieving the same thing:
aDate = (document.getElementById("datepicker").value);
$('.daysContain').find('div').eq(dateArray.length-1).prepend(aDate + '<br>');

Categories

Resources