Get value of integer variable for dynamic loading - javascript

I'm trying to dynamically create elements and add an Event Listener to them. Here's some code:
var marks = {
list:[{
selected: "content",
url: "http://youtube.com/feed/subscriptions",
trait: "id"
},{
selected: "js-streams streams items",
url: "http://twitch.tv/directory/following",
trait: "class"
}]
};
var l = marks.list.length;
var web = "<webview src='https://youtube.com/feed/subscriptions' preload='preload.js' disablewebsecurity></webview>";
for(var i = 0; i < l; i++){
var webadd = "<webview id=web" + i + " src=" + marks.list[i].url + " preload='preload.js' disablewebsecurity></webview>";
$('#canvas1').append(webadd);
document.getElementById("web" + (i)).addEventListener("dom-ready", function() {
console.log("nice" + (i)); // <-- This line most likely needs changing
});
}
Right now, I'm able to get my elements and an event listener on each, but when it comes to console log, it prints out "nice2" twice. Is there a way to get that line to get var i's value as an integer instead of i itself? Ideally, I want it to be printing out nice0 and nice1. Any ideas? Thanks.

You better use a forEach loop. This way you can have a closure and keep you context. also reads better.
mark.list.forEach(function(item, i){
var webadd = "<webview id=web" + i + " src=" + item.url + " preload='preload.js' disablewebsecurity></webview>";
$('#canvas1').append(webadd);
document.getElementById("web" + i).addEventListener("dom-ready", function() {
console.log("nice" + i); // <--
});
})

You need an extra function that creates your event listener and binds the current i to it:
document.getElementById("web" + (i)).addEventListener("dom-ready", (function(n) {
return function() {
console.log("nice" + (n));
}
})(i));

Related

how to get this json object table filter working

I have a website with a list of json objects arranged something like this:
[
{
"a": true or false,
"b": "information",
"c": "information",
"d": "information",
"e": "information"
},
...
]
The idea of this code is to print out all the objects on a table and have a checkbox which filters out the false objects out when needed. The site is supposed to just have the the table with unfiltered object on there, but after I added the checkbox event listener the full table list disappeared. When I check the checkbox I get the filtered objects and it keeps adding more and more of the same filtered content on the bottom of the table if I keep re-clicking it.
What am I doing wrong here? Here is the code I have:
var stuff = document.getElementById("stuff-info");
var ourRequest = new XMLHttpRequest();
ourRequest.open('GET', 'url');
ourRequest.onload = function() {
var ourData = JSON.parse(ourRequest.responseText);
renderHTML(ourData);
};
ourRequest.send();
function renderHTML(data) {
var htmlString = "";
var filteredData = data.filter(function(element) {
return element.a
});
var checkbox = document.querySelector("input[name=hide]");
checkbox.addEventListener('change', function() {
if (this.checked) {
for (i = 0; i < filteredData.length; i++) {
htmlString += "<table><tr><td>" + filteredData[i].b + "</td><td>" + filteredData[i].c + "</td><td>" + filteredData[i].d + "</td><td>" + filteredData[i].e + "</td></tr>"
}
} else {
for (i = 0; i < data.length; i++) {
htmlString += "<table><tr><td>" + data[i].b + "</td><td>" + data[i].c + "</td><td>" + data[i].d + "</td><td>" + data[i].e + "</td></tr>"
}
}
stuff.insertAdjacentHTML('beforeend', htmlString);
});
}
Might be easier to filter with CSS selector:
#filter:checked ~ table .filter { display: none }
<input type=checkbox id=filter> Filter
<table border=1>
<tr class=filter><td>1</td><td>a</td></tr>
<tr><td>2</td><td>b</td></tr>
<tr class=filter><td>3</td><td>c</td></tr>
<tr><td>4</td><td>d</td></tr>
</table>
after I added the checkbox event listener the full table list disappeared.
All of your logic for deciding what to render is trapped inside your onchange event, so nothing will be drawn until a checkbox is changed.
When I check the checkbox I get the filtered objects and it keeps adding more and more of the same filtered.
All of your html strings are generated with += against the original htmlString variable trapped in the closure. So yeah, it will just keep adding more and more rows. You are also inserting the udated strings into the dom without removing the old table(s), so this will be exponential growth.
I think there is a great case here for higher order functions instead of for loops, you can use the map array method to transform each item in the array into a string, instead of manually iterating. This is cleaner and more maintainable.
Notice that now that the rendering logic is not mixed together with the event logic, it would be much easier to reuse the render function with some different data or different events. It's also somewhat trivial to add more transformations or filters.
const ourRequest = new XMLHttpRequest();
ourRequest.onload = function() {
const ourData = JSON.parse(ourRequest.responseText);
initialRender(ourData);
};
ourRequest.open('GET', 'url');
ourRequest.send();
function filterAll() { return true; }
function filterA() { return element.a; }
function toRowString(item) {
return `
<tr>
<td>${item.a}</td>
<td>${item.b}</td>
<td>${item.c}</td>
<td>${item.d}</td>
<td>${item.e}</td>
</tr>`;
}
function renderTable(predicate, parentElement, data){
const rows = data
.filter(predicate)
.map(toRowString);
parentElement.innerHTML = `<table>${rows}</table>`;
}
function initialRender(data) {
const stuff = document.getElementById("stuff-info");
const checkbox = document.querySelector("input[name=hide]");
renderTable(filterAll, stuff, data);
checkbox.addEventListener('change', function(event) {
renderTable(
event.target.checked ? filterA : filterAll,
stuff,
data
);
}
}

How to save values from option to one array cell in a loop

So I got a loop of processes. You can check it here.
So the point is my system can have different number of processes. And for each process there can be more than one studio. What I want to achieve is to save studios under one process into one array cell divided by coma. So later I could use this array and split studios to insert it to database.
My save function:
var LISTOBJ = {
saveList: function() {
$(".output").html("");
$(".studio").each(function() {
var listCSV = [];
$(this).find("input").each(function() {
listCSV.push($(this).text());
});
var values = '' + listCSV.join(',') + '';
$(".output").append("<input type='text' name='studio[]' value='" + values + "' />");
$("#output").append("<p>" + values + "</p>");
console.debug(listCSV);
});
}
}
But it seems it doesnt work. What do I need to change to achieve what i want? Thank you
on html file, on process 1 select option add this to the class attribute process-1, and on the process 2 also add process-2 on class attribute then, modify the saveList function
var processList = {process_1 : [] , process_2 : []};
$(".output").html("");
$(".studio").each(function() {
var text = $(this).val();
var process1 = $(this).hasClass('process-1');
var process2 = $(this).hasClass('process-2');
if(text) {
listCSV.push(text);
if(process1) {
processList.process_1.push(text);
} else if (process2) {
processList.process_2.push(text);
}
}
});
listObj.saveList = listCSV;
var values = listCSV.join(', ');
$(".output").append("<input type='text' name='studio[]' value='" + values + "' />");
$("#output").append("<p>" + values + "</p>");
console.log(processList);
ahh, i think i have solved the first question, about the question #1. on your html file add value attribute on each option. and also remove the div class="studio" hence put the class "studio" on the select class. after that try my code on the javascript file
// everytime the save button is clicked
$('#savebutton').click(function() {
saveList();
});
// set list studio
var listCSV = [];
// your list object
var listObj = {saveList: []};
// save list function
function saveList() {
$(".output").html("");
$(".studio").each(function() {
var text = $(this).val();
if(text) {
listCSV.push(text);
}
});
listObj.saveList = listCSV;
var values = listCSV.join(', ');
$(".output").append("<input type='text' name='studio[]' value='" + values + "' />");
$("#output").append("<p>" + values + "</p>");
}

Replace prototype objects property

<script>
Croppic = function (id, options) {
var that = this;
that.id = id;
that.obj = $('#' + id);
that.outputDiv = that.obj;
};
Croppic.prototype = {
form: {}
};
init: function () {
var that = this;
var cropControlUpload = '';
if (that.options.customUploadButtonId === '') {
cropControlUpload = '<i class="cropControlUpload"></i>';
}
var cropControlRemoveCroppedImage = '<i class="cropControlRemoveCroppedImage"></i>';
if ($.isEmptyObject(that.croppedImg)) {
cropControlRemoveCroppedImage = '';
}
if (!$.isEmptyObject(that.options.loadPicture)) {
cropControlUpload = '';
}
var html = '<div class="cropControls cropControlsUpload"> ' + cropControlUpload + cropControlRemoveCroppedImage + ' </div>';
that.outputDiv.append(html);
var formHtml = '<form class="' + that.id + '_imgUploadForm" style="visibility: hidden;"> <input type="file" name="img" accept="image/*" id="' + that.id + '_imgUploadField"> </form>';
that.outputDiv.append(formHtml);
that.form = that.outputDiv.find('.' + that.id + '_imgUploadForm');
},
reset:function (){
var that=this;
that.init();//This initializes using init function
}
</script>
I have a crop module which does something like above.So everytime reset is called the module is initialized by using the init function.
However, the output is not coming as expected what is happening that when a reset is called more than twice, the form object shows this kind of behavior.
That is what console shows when reset is called the first time.Look for the property 0.
When the reset is called twice the result is something like this.Instead of removing the property 0 , it appended a new property 1.
This thing go on if i make more calls to the reset.
So when this happens Inspector in Mozilla shows more than one form when reset is called more than one time(Here i have called reset twice hence two forms in Inspector).
To overcome this problem i tried deleting the property 0 and even tried deleting the whole object and tried to create a new object but nothing helps.
if(that.form.hasOwnProperty("0"))
{
delete that.form["0"];// Here i even did this delete that.form;
that.form = that.outputDiv.find('.' + that.id + '_imgUploadForm');
}else{
that.form = that.outputDiv.find('.' + that.id + '_imgUploadForm');
}
I did everything but the same thing happens.How do i make sure it doesn't add more properties if 0 exists .If 0 exists just replace 0 by the new one.
Full Code :http://codepad.org/03EiunbL

How to get the value of id of innerHTML?

I have created a html like this:
<body onload = callAlert();loaded()>
<ul id="thelist">
<div id = "lst"></div>
</ul>
</div>
</body>
The callAlert() is here:
function callAlert()
{
listRows = prompt("how many list row you want??");
var listText = "List Number";
for(var i = 0;i < listRows; i++)
{
if(i%2==0)
{
listText = listText +i+'<p style="background-color:#EEEEEE" id = "listNum' + i + '" onclick = itemclicked(id)>';
}
else
{
listText = listText + i+ '<p id = "listNum' + i + '" onclick = itemclicked(id)>';
}
listText = listText + i;
//document.getElementById("lst").innerHTML = listText+i+'5';
}
document.getElementById("lst").innerHTML = listText+i;
}
Inside callAlert(), I have created id runtime inside the <p> tag and at last of for loop, I have set the paragraph like this. document.getElementById("lst").innerHTML = listText+i;
Now I am confuse when listItem is clicked then how to access the value of the selected item.
I am using this:
function itemclicked(id)
{
alert("clicked at :"+id);
var pElement = document.getElementById(id).value;
alert("value of this is: "+pElement);
}
But getting value as undefined.
Any help would be grateful.
try onclick = itemclicked(this.id) instead of onclick = 'itemclicked(id)'
Dude, you should really work on you CodingStyle. Also, write simple, clean code.
First, the html-code should simply look like this:
<body onload="callAlert();loaded();">
<ul id="thelist"></ul>
</body>
No div or anything like this. ul and ol shall be used in combination with li only.
Also, you should always close the html-tags in the right order. Otherwise, like in your examle, you have different nubers of opening and closing-tags. (the closing div in the 5th line of your html-example doesn't refer to a opening div-tag)...
And here comes the fixed code:
<script type="text/javascript">
function callAlert() {
var rows = prompt('Please type in the number of required rows');
var listCode = '';
for (var i = 0; i < rows; i++) {
var listID = 'list_' + i.toString();
if (i % 2 === 0) {
listCode += '<li style="background-color:#EEEEEE" id="' + listID + '" onclick="itemClicked(this.id);">listItem# ' + i + '</li>';
}
else {
listCode += '<li id="' + listID + '" onclick="itemClicked(this.id);">listItem# ' + i + '</li>';
}
}
document.getElementById('thelist').innerHTML = listCode;
}
function itemClicked(id) {
var pElement = document.getElementById(id).innerHTML;
alert("Clicked: " + id + '\nValue: ' + pElement);
}
</script>
You can watch a working sample in this fiddle.
The problems were:
You have to commit the id of the clicked item using this.id like #Varada already mentioned.
Before that, you have to build a working id, parsing numbers to strings using .toString()
You really did write kind of messy code. What was supposed to result wasn't a list, it was various div-containers wrapped inside a ul-tag. Oh my.
BTW: Never ever check if sth. is 0 using the ==-operator. Better always use the ===-operator. Read about the problem here
BTW++: I don't know what value you wanted to read in your itemClicked()-function. I didn't test if it would read the innerHTML but generally, you can only read information from where information was written to before. In this sample, value should be empty i guess..
Hope i didn't forget about anything. The Code works right now as you can see. If you've got any further questions, just ask.
Cheers!
You can pass only the var i and search the id after like this:
Your p constructor dymanic with passing only i
<p id = "listNum' + i + '" onclick = itemclicked(' + i + ')>
function
function itemclicked(id)
{
id='listNum'+i;
alert("clicked at :"+id);
var pElement = document.getElementById(id).value;
alert("value of this is: "+pElement);
}
is what you want?
I am not sure but shouldn't the onclick function be wrapped with double quotes like so:
You have this
onclick = itemclicked(id)>'
And it should be this
onclick = "itemclicked(id)">'
You have to modify your itemclicked function to retrieve the "value" of your p element.
function itemclicked( id ) {
alert( "clicked at :" + id );
var el = document.getElementById( id );
// depending on the browser one of these will work
var pElement = el.contentText || el.innerText;
alert( "value of this is: " + pElement );
}
demo here

the javascript template and the event handling

I have asked a question about how to avoiding to write the html in the js,then some people tell me using the javascript template,for example,the jquery/template pugin and ect.
It is a good idea when generate static html,for example:
<ul id="productList"></ul>
<script id="productTemplate" type="text/x-jquery-tmpl">
<li><a>${Name}</a> (${Price})</li>
</script>
<script type="text/javascript">
var products = [
{ Name: "xxx", Price: "xxx" },
{ Name: "yyy", Price: "xxx" },
{ Name: "zzz", Price: "xxx" }
];
// Render the template with the products data and insert
// the rendered HTML under the "productList" element
$( "#productTemplate" ).tmpl( products )
.appendTo( "#productList" );
</script>
However when I try to bind some event to the generated html,I meet some problem.
For example,I have a page which user can search some products by the price/name/location.
So I have three function:
searchByPrice(lowPrice,highPrice,productType,currentPage)
searchByName(name,productType,currentPage);
searchByLocation(location,currentpage);
ALl the above function have a realated method in the server side and they will retrun the products usint the xml format.
Since they will retrun so many items,so I have to paging them,the "currengPage" is used to tell the server side which part of results should be returned.
When the client get the result from the server side,now it is the js for display them int he div and create a Paging Bar if possible.
Before I know the template,I use this manner(which I hate most,try my best to avoid):
function searchByPrice(lowPrice,highPrice,productType,currentPage){
var url="WebService.asmx/searchByPrice?low="+lowPrice="&high="+highPrice+"&curPage="+currentPage;
//code to create the xmlHttp object
xmlhttp.open("GET",url,true);
xmlhttp.onreadystatechange=function(){
if (xmlhttp.readyState==4 && xmlhttp.status==200){
var i=0;
var Prohtml="";
var proList=parseProductList(xmlhttp.responseText);
for(i=0;i<prolist.length;i++){
Prohtml+="<li><a href='#'>"+prolist[i].name+"</a> ("+prolist[i].price"+)</li>";
}
//generate the paging bar:
var totleResult=getTotleResultNumber(xmlhttp.responseText);
if(totleResult>10){
var paghtml="<span>";
//need the paging
var pagNum=totleResult/10+1;
for(i=1;i<=pagenum;i++){
paghtml+="<a onclick='searchByPrice(lowPrice,highPrice,productType,currentPage+1)'>i</a>";
//here the synax is not right,since I am really not good at handle the single or doule '"' in this manner.
//also if in the searchByName function,the click function here should be replaced using the searchByName(...)
}
}
}
}
}
In the example,it is easy to use the template to generate the "Prohtml" since there is no event handling with them,but how about the "paghtml",the click function is different in differnt search type.
So,any good idea to hanld this?
Either:
Create DOM Elements instead of building HTML strings, using document.createElement or a small library if you're doing lots of this, which will allow you to attach events immediately in the usual fashion.
or
Give each element which needs to make use of event handlers a unique ID and build up a list of events to be attached once the HTML has been inserted into the document.
E.g.:
var eventHandlers = []
, eventCount = 0;
for (i = 1; i <= pagenum; i++) {
var id = "search" + eventCount++;
html += "<a id='" + id + "'>" + i + "</a>";
eventHandlers.push([id, 'click',
handler(searchByPrice, lowPrice, highPrice, productType, currentPage + i)])
}
// Later...
someElement.innerHTML = html;
registerEvents(eventHandlers);
Where registerEvents is:
function registerEvents(eventHandlers) {
for (var i = 0, l = eventHandlers.length; i < l; i++) {
var eventHandler = eventHandlers[i],
id = eventHandler[0],
eventName = eventHandler[1],
func = eventHandler[2];
// Where addEvent is your cross-browser event registration function
// of choice...
addEvent(document.getElementById(id), eventName, func);
}
}
And handler is just a quick way to close over all the arguments passed in:
/**
* Creates a fnction which calls the given function with any additional
* arguments passed in.
*/
function handler(func) {
var args = Array.prototype.slice.call(arguments, 1);
return function() {
func.apply(this, args);
}
}
I use something like this approach (but automatically adding unique ids when necessary) in the HTML generation portion of my DOMBuilder library, which offers a convenience method for generating HTML from content you've defined, inserting it into a given element with innerHTML and registering any event handlers which were present. Its syntax for defining content is independent of output mode, which allows you to switch between DOM and HTML output seamlessly in most cases.
First of all, you can simply use the $.get() or $.ajax() for your AJAX call.
Secondly, you can use .live() or .delegate() to bind events to elements that do not exist.
Thirdly, you can use the data attributes in the anchor elements as a way to pass in the arguments for the event handler, see .data().
So, to rewrite your function, you have may something like the following:
function searchByPrice(event) {
$this = $(this);
var lowPrice = $this.data('lowPrice'),
highPrice = $this.data('lowPrice'),
productType = $this.data('productType'),
currentPage = $this.data('currentPage');
var url = "WebService.asmx/searchByPrice?low=" + lowPrice = "&high=" + highPrice + "&curPage=" + currentPage;
$.get(url, function(data, textStatus, jqXHR) {
var i = 0;
var Prohtml = "";
var proList = parseProductList(data);
for (i = 0; i < prolist.length; i++) {
Prohtml += "<li><a href='#'>" + prolist[i].name + "</a> (" + prolist[i].price "+)</li>";
}
//generate the paging bar:
var totleResult = getTotleResultNumber(data);
if (totleResult > 10) {
var paghtml = "<span>";
//need the paging
var pagNum = totleResult / 10 + 1;
for (i = 1; i <= pagenum; i++) {
paghtml += '<a class="pagelink" ' +
'data-lowPrice="' + lowPrice + '" ' +
'data-highPrice="' + highPrice + '" ' +
'data-productType="' + productType + '" ' +
'data-currentPage="' + (currentpage + 1) + '">' + i + '</a>';
//here the synax is not right,since I am really not good at handle the single or doule '"' in this manner.
//also if in the searchByName function,the click function here should be replaced using the searchByName(...)
}
}
});
}
$(document).ready(function(){
$("a.pagelink").live('click', searchByPrice);
});

Categories

Resources