Hit a slight bump on something.
So I have a spreadsheet feed coming through via json.
Once they are loaded, if they contain a certain word, I want an elment that is already on the page to do something.
Having some trouble.
Here is my code:
/*feed*/
function displayContent(json) {
var len = json.feed.entry.length
var divtag = ''
for (var i=0; i<len; i++) {
divtag += [
'<div id=' +' tooltipwrap' + i + '>' +
'<span style="font-size:22px; font-weight:600;">',
json.feed.entry[i].gsx$studentname.$t + ' ' +
'<span class="hide" style="font-size:18px; font-weight:300;">',
json.feed.entry[i].gsx$classlevel.$t
+ '</span>' + '<span id=' + 'tooltipside' + i +'>' +
json.feed.entry[i].gsx$gender.$t + '-' +
'</span>',
'</div>'
].join('');
}
document.getElementById('tipswrap').innerHTML = divtag
}
/* what I wanted to do */
if ($('#tooltipside0').html() === "Senior") {
$("#test1").addClass('no');
}
Here is the JSFiddle
Pay attention to the tabulation. Right now your code is hard to read because you have failed to do so.
Here:
var len = json.feed.entry.length
var divtag = ''
you are missing semi-colons. You have to put semi-colon at the end of any operation, like this:
var len = json.feed.entry.length;
var divtag = '';
Semi-colons serve as operation separators.
Here:
divtag += [
'' +
'',
json.feed.entry[i].gsx$studentname.$t + ' ' +
'',
json.feed.entry[i].gsx$classlevel.$t
+ '' + '' +
json.feed.entry[i].gsx$gender.$t + '-' +
'',
'</div>'
].join('');
You have multiple problems:
You have failed to put your html attributes into quotes, so the resulting html will be invalid. Also, you have used comma instead of plus at the last concatenation.
CONCLUSION: You are obviously not ready to implement this code, because:
- You lack Javascript syntax knowledge
- You lack HTML syntax knowledge
- You do not pay attention to tabulation
As a consequence, your main problem is not what the question states, namely, how to add a class to an element depending on JSON feed. Your main problem is that you lack Javascript and HTML education. Please, follow some tutorials to be able to solve a problem and after that try again to solve your problem. If you fail to do so, then you will have at least an educated guess.
After adding the content to tipswrap add the condition
document.getElementById('tipswrap').innerHTML = divtag; //$('#tipswrap').html(divtag)
if ($.trim($('#tooltipside0').html()) === "Senior") {
$("#test1").addClass('no');
}
Demo: Fiddle
I recommend you add a class to all of your rows called student and then from there use this javascript:
function displayContent(json) {
var len = json.feed.entry.length
var divtag = ''
for (var i = 0; i < len; i++) {
divtag +=
'<div class="student" id="tooltipwrap'+i+'">'+
'<span style="font-size:22px; font-weight:600;">'+
json.feed.entry[i].gsx$studentname.$t +
'<span class="hide" style="font-size:18px; font-weight:300;">'+
json.feed.entry[i].gsx$classlevel.$t +
'</span> '+
'<span id="tooltipside'+i+'">'+
json.feed.entry[i].gsx$gender.$t + '-' +
'</span>'+
'</span>'+
'</div>';
}
document.getElementById('tipswrap').innerHTML = divtag
}
jQuery(document).ready(function($) {
$('.student').each(function() {
if ($(this).text().toLowerCase().indexOf("senior") >= 0)
$(this).addClass('senior');
});
});
Here's a demo
Related
I am trying to create a function that will add buttons with their corresponding event listeners
var wordCount = 0;
function createButton(word, alert){
document.querySelector('body').innerHTML += "<button id=\"word-" + wordCount + "\">" + word + "</button>";
document.querySelector('#word-' + wordCount).addEventListener('click', function(){
console.log(alert);
})
wordCount++;
}
createButton('a', 'A');
createButton('b', 'B');
Only the last button(b) responds. Clicking button(a) does not output anything.
How would you fix this? Are there better ways that I could have implemented this?
I am frequently facing this situation and doing it in a simpler way. see this, (the beauty of the method is if you start the variable full with single quotes, you can add any usual double quoted stuff within it, with ease and without any escaping issues). No addEventListener business needed here. :-)
var full = '';
var wordCount = 0;
function createButton(word, alert) {
alert='\'' + alert + '\'';
full = full + '<a href="javascript:void(0)" onclick="alert(' + alert + ');">'
full = full + '<button id="word-' + wordCount + '" >' + word + '</button>';
full = full + '</a>';
document.querySelector('body').innerHTML += full;
wordCount++;
}
function anyFunction(alert) {
console.log(alert);
}
createButton('a', 'A');
createButton('b', 'B');
I was given this task with some existing code to change the string color of each of three selector.value(s) that is output onto an input element to three different colors. The code boils the three selectors into a single output variable. Without destroying the code, I cannot figure out how to select each individual variables prior to condensing them.
If I could use the fontcolor() method, my life would be great but it's 2018 and I can't. Is there any way you can think of to solve this issue?To clarify, I need to alter the colors of the strings that belong to output(red), select1.value(blue) and select2.value(black.
Most of the action for this is happening in the parseOutput() function but I'm just stuck and don't think it's possible without rewriting the entire program.
function updateSelector(result){
var options = result.options;
var elementId = "select" + result.element;
var logger = document.getElementById('logger');
var selector = document.getElementById(elementId);
//logger.innerHTML = JSON.stringify(elementId);
selector.innerHTML = options;
selector.disabled = false;
}
google.script.run.withSuccessHandler(updateSelector).processOptions(0);
plate();
function resetAll(){
for (var i = 0;i<3;i++){
var selector = document.getElementById('select' + i);
selector.disabled = true;
selector.innerHTML = "";
}
google.script.run.withSuccessHandler(updateSelector).processOptions(0);
}
function finalSelection(){
var output = document.getElementById('out');
//output.focus();
output.select();
}
function plate(){
var plate = document.getElementById('plate');
plate.innerHTML = atob('Q3JhZnRlZCBieTogWmFjaGFyeSBTdGFjaG93aWFr');
}
//Adds the location as initial output, followed by divider, application, and issue if select1 is selected
//else statement added so if select0 is [Costco Website Name], to ommit the " - "
function parseOutput(){
var output = "";
if (select1.value.length > 0 && select0.value !== "[Costco Website Name]"){
output = output + ' - ' + select1.value + ' // ' + select2.value;
} else{
output = output + select1.value + ' // ' + select2.value;
}
out.value=output.trim();
}
And this is the Div that displays the output:
<div class="wide"><p><input class="wide" type="readonly" id="out" onfocus="this.select();"></p></div>
A modern replacement for fontcolor would use a span and a style (or class), e.g.:
function modernFontColor(str, color) {
return '<span style="color: ' + color + '">' + str + '</span>';
}
or
function modernFontClass(str, cls) {
return '<span class="' + cls + '">' + str + '</span>';
}
...where the class defines the styling.
I'm trying to use a Bootstrap Tab plugin for CKEditor, and it works well. But, when i use a single quote on content (doesn't matter if the string is "'", or " or '), it broke up.
I guess is just a escape issue. I tried with escape() and encodeURI(), but fails.
Error: SyntaxError: missing ) after argument list;
Source:
x)PRE3015 Pino 1/2'' 15mm Ponta Balistica Aço 3,1 15
The piece of plugin code for tabs is:
data: function() {
var bootstrapTab_d = new Date();
var bootstrapTab_id = bootstrapTab_d.getTime();
var bootstrapTab_item = bootstrapTab_contents = '';
for (var bootstrapTab_i = 0; bootstrapTab_i <= this.data.bootstrapTab_total; bootstrapTab_i++) {
eval("bootstrapTab_title = this.data.bootstrapTab_item" + bootstrapTab_i);
bootstrapTab_title = bootstrapTab_title != undefined ? bootstrapTab_title : '';
eval("bootstrapTab_content = this.data.bootstrapTab_content" + bootstrapTab_i);
bootstrapTab_content = bootstrapTab_content != undefined ? bootstrapTab_content : '';
eval("bootstrapTab_itemClass = this.data.bootstrapTab_itemClass" + bootstrapTab_i);
bootstrapTab_itemClass = bootstrapTab_itemClass != undefined ? bootstrapTab_itemClass : '';
eval("bootstrapTab_contentClass = this.data.bootstrapTab_contentClass" + bootstrapTab_i);
bootstrapTab_contentClass = bootstrapTab_contentClass != undefined ? bootstrapTab_contentClass : '';
if (bootstrapTab_title) {
bootstrapTab_item += '<li role="presentation" class="' + bootstrapTab_itemClass + '">' + bootstrapTab_title + '</li>';
bootstrapTab_contents += '<div role="tabpanel" class="' + bootstrapTab_contentClass + '" id="tab' + bootstrapTab_id + '_' + (bootstrapTab_i + 1) + '">' + bootstrapTab_content + '</div>'
}
}
this.element.setAttribute('id', 'collapse' + bootstrapTab_id);
this.element.$.innerHTML = '<div role="tabpanel"><ul class="nav nav-tabs" role="tablist">' + bootstrapTab_item + '</ul><div class="tab-content">' + bootstrapTab_contents + '</div></div>'
}
I'd refactor the code, and not use eval!
eval is evil http://blogs.msdn.com/b/ericlippert/archive/2003/11/01/53329.aspx
instead of
eval("bootstrapTab_title = this.data.bootstrapTab_item" + bootstrapTab_i);
use bootstrapTab_item as an array and do this
bootstrapTab_title = this.data.bootstrapTab_item[bootstrapTab_i]
really don't know if the error is there, but I think the path to find the error is refactor to eliminate those eval, that could be the source of your problem.
In my javascript app, I insert a user message using the code:
var displayMessages = function(response, onBottom) {
var user = GLOBAL_DATA.user;
var acc = '';
for(var i=0; i<response.length; i+=1) {
var obj = response[i];
var acc_temp = "";
acc_temp += '<div class="message ' + (obj['user_id']==user['id'] ? 'message-right' : 'message-left') + '">';
acc_temp += '<div>' + Autolinker.link($(obj['message']).text()) + '</div>';
if (obj['user_id']!=user['id']) {
acc_temp += '<div class="message-details">' + obj['first_name'] + ' ' + obj['last_name'] + '</div>';
}
acc_temp += '<div class="message-details">' + obj['date_sent'] + '</div>';
acc_temp += '</div>';
acc = acc_temp + acc;
}
addMessage(acc, onBottom);
};
The problem is that, if obj['message'] = "<script>alert(1);</script>"; then what gets printed on the screen is "alert(1);" because I use .text(). How can I insert the string with the script tags, so that it looks exactly like that on the page? I don't want it to get executed.
Thanks
I use these helper functions.
function htmlEncode(value){
return $('<div/>').text(value).html();
}
function htmlDecode(value){
return $('<div/>').html(value).text();
}
I would escape the other variables as well if you are not sure that they will not have any executable code.
I solved it using this:
function escapeHTML(str) {
return $("<p></p>").text(str).html();
}
I think you'll need to wrap your object in a dummy tag, then you can retrieve the full html from that.
You'll have issues though, because you're using a script tag, which will be evaluated.
obj['message'] = "<script>alert(1);</script>";
>
$(obj['message']).text();
> "alert(1);"
$(obj['message']).html();
> "alert(1);"
$(obj['message']).wrapAll('<div>').text();
// alerts with 1
> "alert(1);"
Not using a script tag will work.
obj['message'] = "<span>alert(1);</span>";
>
$(obj['message']).wrapAll('<div>').text();
> "<span>alert(1);</span>"
I have a method called refreshHistory() that basically reads locally stored list of json (using https://github.com/marcuswestin/store.js/) and populates a list in the order they were stored at.
Everytime a user action happens, this method is called. But as the list gets bigger and bigger, it slows down the browser to a crawl.
function refreshHistory() {
var records = typeof store.get('history') == "undefined" ? 0 : store.get('history').history;
;
if (records == 0) {
$('#content #historyView').html('<i>history show up here in order.</i>');
} else {
var xhistory = '<div id="history">';
for (var i = 0; i < records.length; i++) {
var xaction = records[i]
xhistory += '<div id="action">' + (i + 1) + '. ' + '<b>' + xaction.action + "</b> " + xaction.caption + '<span class="delaction" id=' + i + ' data-stamp="' + xaction.msg + '" style="color:red;cursor:pointer;">' + '[remove]' + '</span></div>'
}
xhistory += "</div>"
$('#qtip-0-content #historyView').html(xhistory);
}
}
Rendering everything on every event is a simple strategy, which is good, but it does run into the performance problems you are describing. It's hard to give specific advice, but you could either:
Implement a more detailed rendering logic, where only new items are rendered and added to the DOM.
Use ReactJs or Virtual DOM libraries, which allow your code to use the render everything pattern, but make the actual updates to the DOM faster by doing the minimum needed.
The only way to really make this efficient is to implement it in a different way.
I've been using knockout.js personally and am very happy with it. Basically you write a template and the library handles the DOM node changes, only updating the parts needed. You will need to learn how to think slightly differently, but there are some great tutorials available.
That said, one simple trick you can try is move the selectors outside the function so they are only ran once instead of each time you call the function.
For sanity I would also keep records variable the same type whether or not the .get('history') returns undefined.
var contentHistoryView = $('#content #historyView');
var qtipHistoryView = $('#qtip-0-content #historyView');
function refreshHistory() {
var records = typeof store.get('history') == "undefined" ? [] : store.get('history').history;
if (records.length) {
contentHistoryView.html('<i>history show up here in order.</i>');
} else {
var xhistory = '<div id="history">';
for (var i = 0; i < records.length; i++) {
var xaction = records[i]
xhistory += '<div id="action">' + (i + 1) + '. ' + '<b>' + xaction.action + "</b> " + xaction.caption + '<span class="delaction" id=' + i + ' data-stamp="' + xaction.msg + '" style="color:red;cursor:pointer;">' + '[remove]' + '</span></div>'
}
xhistory += "</div>"
qtipHistoryView.html(xhistory);
}
}
I doubt this will have a huge impact though, as I suspect most of the execution time is spent in the loop.