I'm working on a .NET Core project for my company where work orders are loaded from our SQL database using Entity Framework, filtered and then displayed as markers on a map through Google Maps API for our installers.
We have two types of filters: one that gets included in an Ajax POST, and one that filters locally to decrease load times and performance issues. What I'm trying to do is load the local filter items (lists that are included in the response when calling the initial Ajax POST). If the list of filter items exceeds 5 items, I want them to collapse to only 5 items and insert an anchor which expands (utilizes jQuery's toggle()) showing the rest of the items in that list.
This is the excerpt from the JavaScript function which takes care of that:
filterItems
.forEach((filterItem, i) => {
var localItem = '<label class="' + selectorContainerClass
+ ' selectorContainer" id="' + selectorContainerIdPrefix + filterItem.key
+ '"><input id="' + convertValToEng(filterItem.value)
+ '" type = "checkbox" class="filled-in navy" name="' + inputName
+ '" value="' + filterItem.key
+ '" onchange="localFilter(this, this.value)" /><span class="selector-value">'
+ filterItem.value
+ '</span> <span id="' + paramName + 'Cnt__' + filterItem.key
+ '" class="selector-count"></span></label ><br />';
document.querySelector("#" + colId).insertAdjacentHTML('beforeend', localItem);
if (i >= 5) {
$("#" + colId + " #" + selectorContainerIdPrefix + filterItem.key).addClass("collapse");
$("#" + colId + " #" + selectorContainerIdPrefix + filterItem.key).toggle(100);
$("#" + colId + " #" + selectorContainerIdPrefix + filterItem.key + " + br").toggle(100);
}
});
if (filterItems.length > 5) {
//TODO: Fix the bug here; the .filter-collapse element is not being inserted under local installers.
var newEl = '<a class="filter-collapse" onclick="toggleFilterExpand(false, this)";><i class="material-icons">expand_more</i></a>';
document.getElementById(colId).insertAdjacentHTML('beforeend', newEl);
}
I should be getting a newEl inserted under the "Installer" column (8 installers, 3 of them not being displayed), but I'm not. I've tried jQuery's after() and insertAfter() methods, but neither of those worked. newEl is being generated for the "Area" column, as it should, but for the "Installer" column it's not.
I've also tried inserting the element manually through the console window with the exact same code and it works.
Would appreciate some help with this as I feel lost regarding this issue.
Thanks.
It turned out to be a stupid mistake on my end where I was removing the element newEl from the all the other filter lists before inserting a new one to the currently iterated one.
weird little bug I can't figure out, I have the following line:
$("#ingredientlist").append('<li>' + value + ' parts ' + capitalize(index + '') + '</li>').css("color", curColor);
Basically, in a previous statement I get curColor, which is different depending on what value I'm on. I checked the colors and they're different each time. I want each <li> to be styled to a specific color, so I tried setting the .css() to that, but all my entries are the same color. Any ideas?
Thanks
Currently you are appending li to $("#ingredientlist") then setting its color
You need to set color of li not its parent.
Use
$("#ingredientlist").append(
$('<li></li>')
.text(value + ' parts ' + capitalize(index + ''))
.css("color", curColor)
);
The issue is because append() returns the parent element, not the one which was appended. This means that your code is actually setting the color of the #ingredientlist element, not the li. Try this instead:
$('<li />', { text: value + ' parts ' + capitalize(index + '') })
.css('color', curColor)
.appendTo('#ingredientlist');
You're applying the .css call to the #ingredientlist set, not the li you're appending.
Instead:
$("#ingredientlist").append($('<li>' + value + ' parts ' + capitalize(index + '') + '</li>').css("color", curColor));
// Changes -----------------^^-------------------------------------------------------------------------------------^
Breaking that up into parts just to make it clearer:
var $li = $('<li>' + value + ' parts ' + capitalize(index + '') + '</li>');
$li.css("color", curColor);
$("#ingredientlist").append($li);
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]);
}
What I'm trying to do here is make one function that does all the functionality for a custom select element. So I made a function that accepts three parameters which are defined in the function itself (see code below for more detail). I'm trying to accomplish the following: I want the parameters to be the IDs of the various elements (the wrapper div for example), and I want those parameters to be dropped in the function. My Code is below. Thanks so much
function createList(ParentDivID,SelectMenuID,ListMenuID) {
$('#' + ParentDivID + "'");
$('#' + SelectMenuID + "'");
$('#' + ListMenuID + "'");
var options = $("#" + SelectMenuID +'"' ).find("option");
$(options).each(function(){
$(ul).append('<li>' +
$(this).text() + '<span class="value">' +
$(this).val() + '</span></li>');
});
var ul = '<ul id="' + ListMenuID + "></ul>";
$('#' + ParentDivID + "'").append(ul).end().children('#' + ListMenuID + "'").hide().click(function(){$(ul).slideToggle();});
$("#" + SelectMenuID + '"').hide();
}
createList(fancySelectLarge,selectWalkerType,walkerTypeLi);
At a guess, it is probably because your ids don't end in quote characters (which aren't allowed in ids in HTML 4), but you are appending them to the strings you are searching for with jQuery.
You only need to do your selectors like this
$('#' + ParentDivID);
Also you need to stop interchanging 's and "s because it is causing you to miss some closing quotes
function createList(ParentDivID,SelectMenuID,ListMenuID) {
var options = $('#' + SelectMenuID).find('option');
$(options).each(function(){
$(ul).append('<li>' +
$(this).text() + '<span class="value">' +
$(this).val() + '</span></li>');
});
var ul = '<ul id="' + ListMenuID + '"></ul>';
$('#' + ParentDivID).append(ul).end().children('#' + ListMenuID).hide().click(function(){$(ul).slideToggle();});
$('#' + SelectMenuID).hide();
}
createList(fancySelectLarge,selectWalkerType,walkerTypeLi); `
You are messing up all of your string concatenations like:
$('#' + ParentDivID + "'"); should be $('#' + ParentDivID);
It's generally a bit of a mess but I've tried to fix as much as possible.
function createList(ParentDivID,SelectMenuID,ListMenuID) {
var options = $("#" + SelectMenuID).find("option");
var ul = $('<ul>', {id: ListMenuID});
$(options).each(function(){
ul.append('<li>' +
$(this).text() + '<span class="value">' +
$(this).val() + '</span></li>');
});
$('#' + ParentDivID)
.append(ul)
.end()
.children('#' + ListMenuID)
.hide()
.click(function() { ul.slideToggle(); });
$("#" + SelectMenuID).hide();
}
When you call the function, are the three parameters already variables assigned elsewhere in your code? If not, and the are actually the string id attributes, you need to enclose them in quotes.
createList("fancySelectLarge", "selectWalkerType", "walkerTypeLi");
Note: See other valuable responses about the incorrect quoting in $('#' + ParentDivID + "'");
$(ul) is undefined when execution reaches it, because var ul is only declared a few lines later on. You will also need to use document.body.createElement('ul') instead of putting '<ul ...>' in a string.
Also, the lines $('#' + ParentDivID + "'"); don't do anything.
You need to define ul before using it. Also, define it as $('<ul.../>') not just '<ul.../>', so that you can create a jQuery element from that definition.
and you want also try to create the dom element like this
$('<span class="value">') instead of a string value '<span class="value">'.
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