Here is my function:
function updateRecord(id, textEl) {
db.transaction(function(tx) {
tx.executeSql("UPDATE products SET product = ? WHERE id = ?", [textEl.innerHTML, id], null, onError);
});
}
Here is the call:
<span contenteditable="true" onkeyup="updateRecord('+item['id']+', this)">'+
item['product'] + '</span>
I would like to add a parameter to the call so that I can use the function for multiple columns. Here is what I'm trying but it doesn't work:
<span contenteditable="true" onkeyup="updateRecord('+item['id']+', "product", this)">'+
item['product'] + '</span>
function updateRecord(id, column, textEl) {
db.transaction(function(tx) {
tx.executeSql("UPDATE products SET " + column + " = ? WHERE id = ?", [textEl.innerHTML, id], null, onError);
});
}
They should do the exact same thing, I only specified the product column in the call instead of in the function. Is my syntax incorrect, am I missing something?
Edit:
Here is the full function in which the call is located:
// select all records and display them
function showRecords() {
document.getElementById('results').innerHTML = '';
db.transaction(function(tx) {
tx.executeSql("SELECT * FROM products", [], function(tx, result) {
for (var i = 0, item = null; i < result.rows.length; i++) {
item = result.rows.item(i);
document.getElementById('results').innerHTML +=
'<li><span contenteditable="true" onkeyup="updateRecord('+item['id']+', "product", this)">'+
item['product'] + '</span> x</li>';
}
});
});
}
Update: Ok, then the issue only lies in using double quotes for product. Use single quotes and escape them:
document.getElementById('results').innerHTML +=
'<li><span contenteditable="true" onkeyup="updateRecord('+item['id']+', \'product\', this)">' + ...;
But you really should consider to refactor your code. E.g. you could write it like this:
var results = document.getElementById('results');
var container = document.createDocumentFragment();
for (var i = 0, l = result.rows.length; i < l; i++) {
var item = result.rows.item(i);
var li = document.createElement('li');
var span = document.createElement('span');
span.setAttribute('contenteditable', 'true');
span.onkeyup = (function(item) {
return function() {
updateRecord(item['id'], 'product', this);
}
}(item));
span.innerHTML = item['product'];
var a = document.createElement('a');
a.href = '#';
a.onclick = (function(item) {
return function() {
deleteRecord(item['id'])
}
}(item));
a.innerHTML = 'x';
li.appendChild(span);
li.appendChild(a);
container.appendChild(li);
}
results.appendChild(container);
It is more code but easier to maintain in the long run...
You have syntax and quotation issues. This should work:
onkeyup="updateRecord('item[\'id\']', 'product', this)"
But the code seems a bit weird to me. Is this in your actual HTML or are you echoing or printing it? Because
<span...>'+ item['product'] + '</span>
looks weird in HTML. It will literally put '+ item['product'] + ' inside the <span> tag. Please post a more complete version of your code.
Related
Can you explain the functions below:
viz = new tableau.Viz(containerDiv, url, options);
function listenToMarksSelection() {
viz.addEventListener(tableau.TableauEventName.MARKS_SELECTION, onMarksSelection);
}
function onMarksSelection(marksEvent) {
return marksEvent.getMarksAsync().then(reportSelectedMarks);
}
function reportSelectedMarks(marks) {
var html = "";
for (var markIndex = 0; markIndex < marks.length; markIndex++) {
var pairs = marks[markIndex].getPairs();
html += "<b>Mark " + markIndex + ":</b><ul>";
for (var pairIndex = 0; pairIndex < pairs.length; pairIndex++) {
var pair = pairs[pairIndex];
html += "<li><b>Field Name:</b> " + pair.fieldName;
html += "<br/><b>Value:</b> " + pair.formattedValue + "</li>";
}
}
}
This function just listen the selected mark
This one throw the selection in reportSelectedMarks
It take the marks and write it in an HTML file in a '<'li'>'.
The fieldname would probably be a String and in the value it depend what you are workin with.
So basically these functions would be useful to dynamically print a selected mark on a graph or something like that and print a fielname and a value for that one.
I have array of misspelled words(window.essaySpellingErrors).I have an essay text which is saved in the database from tinyMCE editor.(data.data.essay).
I want to render this essay text in div for teacher so that teacher can evaluate the essay.
But the issue is that i am not able to highlight properly the misspelled words in the essay while rendering. Also i want the start index and end index of the first occurrence of every misspelled word.
So that next time whenever the essay loads the highlights can be made from the start index and end index i saved previously.
I am using rangy for highlight making with angular along with some javascript.
Here i am attaching the code which loops every element of the misspelled words.
Here $scope.comments indicates the comments which teacher makes on essay and loads everytime whenever teacher opens to evaluate essay.When there is no comment added in the system by default misspelled comments are added in the comment box.
$scope.getEssayDetails = function(){
// Set the essay content.
// Write ajax call to get the essay content
$http({
method : 'POST',
url : Helpers.constants['CONTROLLER_PATH'] + 'essayAllotment/getEssay',
data : $.param({'eMode':eMode ,'essayScoreID':eScoreID}), //forms user object
headers : {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
}).success(function(data) {
if(Helpers.ajax_response( '' , data , [] )){
$scope.getEvaluationEssay($.parseJSON(data.result_data));
}
}).error(onAjaxError);
};
$scope.getEvaluationEssay=function(data, extraParams)
{
$("#essay_detail").html("");
$scope.comments = [];
$scope.togglecomment = false;
$scope.comments = [];
$scope.essayDetails = {};
window.essaySpellingErrors=[];
if(data.data.essaySpellingErrors!=undefined)
window.essaySpellingErrors=data.data.essaySpellingErrors;
data.data.essay=data.data.essay.replace(/ +/ig,' ');
//essayPlainText=data.data.essay.replace(/<span class=\'sp_err\'>(.*?)<\/span>/g,"$1");
//essayPlainText=essayPlainText.replace(/<span class=\'for_err\'>(.*?)<\/span>/g,"$1");
//essayPlainText=essayPlainText.replace(/\n/ig,' ');
//essayPlainText=essayPlainText.replace(/\s+/ig,' ');
essayPlainText=data.data.essay;
$("#essay_detail").html(essayPlainText);
if (data.data.report.selectFeedback != "") {
var sfbck = data.data.report.selectFeedback.split('{|~|}');
var commentStr;
for (var i = 0; i < sfbck.length; i++) {
var sfbi = sfbck[i].split('|*|');
if ((sfbi).length != 3) continue;
sfbi.push(i);
$scope.createCommentBox(sfbi);
var indexArr = sfbi[0].match(/\[(.*?)\]/);
commentStr=indexArr[1];
indices=sfbi[1].split('~');
startIndex=indices[0];
endIndex=indices[1];
//startIndex=new RegExp('\\b' + commentStr + '\\b');
//endIndex=startIndex+commentStr.length;
if (!el) el = document.getElementById('essay_detail');
if (!sel) sel = rangy.getSelection();
if (!range) range = rangy.createRange();
range.selectCharacters(el, startIndex, endIndex);
sel.setSingleRange(range);
$scope.setHilights(0,'',0);
}
data.data.essay=$("#essay_detail").html();
}else if(Object.keys(window.essaySpellingErrors).length>0){
for (var i = 0; i < window.essaySpellingErrors.length; i++) {
var spellWord=window.essaySpellingErrors[i];
var regex = new RegExp('\\b' + spellWord + '\\b','gi');
startIndex = $("#essay_detail").text().search(regex);
//endIndex=essayPlainText.indexOf(spellWord);
var results = new Array();//this is the results you want
while (regex.exec($("#essay_detail").text())){
results.push(regex.lastIndex);
}
endIndex=startIndex+spellWord.length;
var title='Comment for [' + spellWord + ']';
var label=startIndex + '~' + endIndex;
var commentText="Misspelt : "+spellWord;
var commentIndex=$scope.comments.length;
var commentObj=[title,label,commentText,commentIndex];
$scope.createCommentBox(commentObj);
if (!el) el = document.getElementById('essay_detail');
if (!sel) sel = rangy.getSelection();
if (!range) range = rangy.createRange();
range.selectCharacters(el, startIndex, endIndex);
sel.setSingleRange(range);
$scope.setHilights(0, '',1);
// }
//$scope.togglecomment = true;
}
data.data.essay=$("#essay_detail").html();
}
$scope.createCommentBox = function(commentObj){
var commentObject = { 'comment' : {'commentFor' : commentObj[0] , 'commentRange' : commentObj[1] , 'commentText' : commentObj[2], 'commentIndex' : commentObj[3]}};
$scope.comments.push(commentObject);
};
$scope.setHilights=function(n, evalNum , isSpellErrorComment) {
//console.log('set HiliteN');
var commentText="";
rSel = rangy.getSelection(); //console.log(rSel);
var txt = rSel.toHtml().replace(/style="background-color:#ff0000"/g, 'class="commentHilight" name="' + parseInt(startIndex) + '~' + parseInt(endIndex) + '"');
var textK = rSel.text();
//console.log(rSel.toHtml()+'------'+txt+'--------'+textK);
rRange = rSel.getRangeAt(0);
rRange.deleteContents();
var str='<span class="commentHilight startIndex-'+ parseInt(startIndex) +' endIndex-'+parseInt(endIndex)+'" label="' + parseInt(startIndex) + '~' + parseInt(endIndex) + '">' + textK + '</span>';
var node = rRange.createContextualFragment(str);
rRange.insertNode(node);
rSel.removeAllRanges();
return;
}
function makeUL() {
var products = JSON.parse(localStorage["products"]);
var list = document.createElement('ul');
for(var i = 0; i < products.length; i++) {
if(products[i].amount == 0) {
continue;
}
// Create the list item:
var item = document.createElement('li');
var product = products[i];
var totalPrice = product.amount * product.price;
var toDisplay = product.name + " " + product.amount + " #" + totalPrice + " ";
// Set its contents:
item.appendChild(document.createTextNode(toDisplay));
var inputbox = document.createElement("input");
inputbox.setAttribute("id", "inputboxProduct" + i);
inputbox.addEventListener("change", function(){
changeAmountProd(inputbox.id);
});
item.appendChild(inputbox);
// Add it to the list:
list.appendChild(item);
}
// Finally, return the constructed list:
return list;
}
This will basically make a list when you hover over a certain string. The list will be based on the localstorage and make an inputbox for each point of that list.
The problem is the adding of eventlisteners. For some reason it always returns an empty value when the event is triggered of that inputbox.
function changeAmountProd(inputboxId) {
var products = JSON.parse(localStorage["products"]);
value = document.getElementById(inputboxId).value;
if(value < 1) {
return;
}
products[i].amount = value;
localStorage["products"] = JSON.stringify(products);
makeUL();
}
The problem is with the callback of your change event. You're referring to the changed element using the inputbox variable (that is available through the closure) but by the time your callback is invoked, inputbox will always point to the last generated element.
Try this instead:
inputbox.addEventListener("change", function(){
changeAmountProd(this.id);
});
See addEventListener
Try this:
function makeUL() {
var products = JSON.parse(localStorage["products"]);
var list = document.createElement('ul');
for(var i = 0; i < products.length; i++) {
if(products[i].amount == 0) {
continue;
}
// Create the list item:
var item = document.createElement('li');
var product = products[i];
var totalPrice = product.amount * product.price;
var toDisplay = product.name + " " + product.amount + " #" + totalPrice + " ";
// Set its contents:
item.appendChild(document.createTextNode(toDisplay));
var inputbox = document.createElement("input");
inputbox.setAttribute("id", "inputboxProduct" + i);
inputbox.addEventListener("change", function(){
changeAmountProd(this.id);
});
item.appendChild(inputbox);
// Add it to the list:
list.appendChild(item);
}
// Finally, return the constructed list:
return list;
}
I was using SQLite in html5 and it worked fine. But the thing was the rows which I was displaying in the page itself were not looking that good. I used innerhtml for displaying the rows as inserted by the user.
Here is the script
function showRecords() {
results.innerHTML = '';
// This function needs a single argument, which is a function that takes
// care of actually executing the query
db.transaction(function(tx) {
tx.executeSql(selectAllStatement, [], function(tx, result) {
dataset = result.rows;
for ( var i = 0, item = null; i < dataset.length; i++) {
item = dataset.item(i);
results.innerHTML += '<li>' + item['lastName'] + ' , '
+ item['firstName']
+ ' <a href="#" onclick="loadRecord(' + i
+ ')">edit</a> '
+ '<a href="#" onclick="deleteRecord(' + item['id']
+ ')">delete</a></li>';
}
});
});
}
/**
* Loads the record back to the form for updation
*
* #param i
*/
function loadRecord(i) {
var item = dataset.item(i);
firstName.value = item['firstName'];
lastName.value = item['lastName'];
phone.value = item['phone'];
id.value = item['id'];
}
/**
* Delete a particular row from the database table with the specified Id
*
* #param id
*/
function deleteRecord(id) {
db.transaction(function(tx) {
tx.executeSql(deleteStatement, [ id ], showRecords, onError);
});
resetForm();
}
So in the code showRecords() method, I have hard coded the data to be displayed. What I want is, that data should be displayed in proper tabular format. I know I have to create elements in JavaScript for dynamic table generation but I am unable to do so and also to display the contents inside table.
Everytime user fills up the form and clicks insert button, insert statement gets executed and then showRecords() method is invoked. I am not able to figure out the proper soluton.
For a pure JavaScript solution, I think this (untested) will work:
function loadRecord(i) {
var item = dataset.item(i);
firstName.value = item.firstName;
lastName.value = item.lastName;
phone.value = item.phone;
id.value = item.id;
}
function showRecords() {
results.innerHTML = '';
// This function needs a single argument, which is a function that takes
// care of actually executing the query
db.transaction(function (tx) {
var i = 0,
table = document.createElement('table'),
tbody = document.createElement('tbody');
tx.executeSql(selectAllStatement, [], function (tx, result) {
var tr = {},
tdName = {},
tdEdit = {},
tdDel = {},
span = {},
aEdit = {},
aDel = {};
dataset = result.rows;
for (i = 0, item = null; i < dataset.length; i += 1) {
//create new table elements
tr = document.createElement('tr');
tdName = document.createElement('td');
tdEdit = document.createElement('td');
tdDel = document.createElement('td');
aEdit = document.createElement('a');
aDel = document.createElement('a');
//grab dataset row
item = dataset.item(i);
//set the name
tdName.innerText = item.lastName + ' , ' + item.firstName;
//create the edit link
aEdit.href = '#';
aEdit.onclick = loadRecord(i);
aEdit.innerText = ' edit ';
tdEdit.appendChild(aEdit);
//create the delete link
aDel.href = '#';
aDel.onclick = deleteRecord(item.id);
aDel.innerText = ' delete ';
tdDel.appendChild(aDel);
//append to row
tr.appendChild(tdName);
tr.appendChild(tdEdit);
tr.appendChild(tdDel);
//append to body
tbody.appendChild(tr);
}
});
table.appendChild(tbody);
results.innerHTML = table.outerHTML;
});
}
/**
* Delete a particular row from the database table with the specified Id
*
* #param id
*/
function deleteRecord(id) {
db.transaction(function (tx) {
tx.executeSql(deleteStatement, [id], showRecords, onError);
});
resetForm();
}
I'm trying to build a database based on some arbitrary data on a website. It's complex and changes for each site so I'll spare the details. Here's basically what I'm trying to do
function level0(arg) { textarea.innerHTML += arg + ' = {'; }
function level1(arg) { textarea.innerHTML += '\n\t' + arg + ': ['; }
function level2(arg) { textarea.innerHTML += arg + ', '; }
And so on. The thing is some level1's don't have any children and I can't get the formatting right.
My three problems are as follows.
The ending commas are going to break in IE (thank you MS)
Empty level1's shouldn't be printed if they don't have any children
Closing /curly?brackets/
HERE'S A DEMO of what I have so far. Notice the ending commas, the empty sub2 which shouldn't be printed, and no closing brackets or braces
Do I need to redesign the entire thing?
Is there also a way to have this all in one function so I don't have to worry if I add another layer?
EDIT
This needs to be done in a string format, I can't build an object and then stringify it, mostly because I need to know which element I'm in the middle of adding to.
Overall it looks that you still might want to build an object, but in case you insist on not building it - here is some sample solution:
function Printer() {
var result = '',
lastLevel = null,
close = {0:'\n}', 1:']', 2:''},
delimiter = {0: ',\n', 1:',\n', 2:','};
function closeLevel(level, noDelimiter) {
if(lastLevel === null)
return;
var l = lastLevel, d = level == lastLevel;
while(l >= level) {
result += close[l] + (l == level && !noDelimiter ? delimiter[l]:'');
l--;
}
}
this.level0 = function(arg) {
closeLevel(0);
result += arg + ' = {\n';
lastLevel = 0;
};
this.level1 = function(arg) {
closeLevel(1);
result += '\t' + arg + ': [';
lastLevel = 1;
};
this.level2 = function(arg) {
closeLevel(2);
result += arg;
lastLevel = 2;
};
this.getResult = function() {
closeLevel(lastLevel, true);
return result;
}
}
var p = new Printer();
p.level0('head');
p.level1('sub1');
p.level2('item1');p.level2('item2');p.level2('item3');
p.level1('sub2');
p.level1('sub3');
p.level2('newthing');
p.level0('head2');
document.getElementById('textarea').value = p.getResult();
You could see it in action here.
I'm not sure why you're building what looks like objects with nested arrays, using string concatenation. Something like this would be much simpler, since it wouldn't require fixing trailing commas, etc:
Edit: I've updated the code to make it keep track of the last level put in.
function Db() {
var level0, level1;
var data = new Object();
this.level0 = function(arg) {
level0 = new Object();
data[arg] = level0;
}
this.level1 = function(arg) {
level1 = new Array();
level0[arg] = level1;
}
this.level2 = function(arg) {
level1.push(arg);
}
this.toString = function() {
var s = '';
for(i in data) {
s += i + '\n';
for(j in data[i]) {
if(data[i][j].length>0) {
s += '\t' + j + ': [' + data[i][j] + ']\n' ;
}
}
}
return s;
}
}
Use like this:
var db = new Db();
db.level0('head');
db.level1('sub1');
db.level2('item1');db.level2('item2');db.level2('item3');
I've tested this in the demo you linked and it works just fine.