I'm listing my products like in the following image.
I want to add delete event to my delete buttons.
My product card html creator function looks like this.
getCardSummaryView: function(card) {
var html = "";
html += "</br>";
html += "<div>";
html += "<label>Product Name: " + card.Product.Name + "</label></br>";
html += "<button id='deleteCard" + card.Product.Id + "'>Delete</button>";
html += "</div>";
return html;
}
array.forEach(response.products, function (item) {
var view = this.getCardSummaryView(item);
dom.byId("sideBar").innerHTML += view;
var node = dom.byId("deleteCard" + item.Id);
on(node, "click", function (e) {alert("something");})
}
But if I add 3 product to panel, only last button click is populating, others doesn't work.
What am I doing wrong?
I believe the following line is problematic because on each iteration, you're rebuilding the DOM and destroying all the event listeners that you just added.
dom.byId("sideBar").innerHTML += view;
You can simply appendChild instead.
http://jsfiddle.net/rayotte/8uRXe/356/
require([
"dojo/_base/array"
, "dojo/dom"
, "dojo/dom-construct"
, "dojo/on"
, "dojo/domReady!"
], function (
array
, dom
, domConstruct
, on
) {
var getCardSummaryView = function (product) {
var html = "";
html += "<br/>";
html += "<div>";
html += "<label>Product Name: " + product.Name + "</label><br/>";
html += "<button type='button' id='deleteCard" + product.Id + "'>Delete</button>";
html += "</div>";
return html;
}
var products = [
{
Id: 1
, Name: 'Product 1'
}
,{
Id: 2
, Name: 'Product 2'
}
,{
Id: 3
, Name: 'Product 3'
}
]
var sideBarNode = dom.byId("sideBar");
array.forEach(products, function (product) {
sideBarNode.appendChild(domConstruct.toDom(getCardSummaryView(product)));
on(dom.byId("deleteCard" + product.Id), 'click', function(e){
console.log('testing' + product.Id)
})
});
});
If i Where You i would do it this way because while you can see the buttons is created but that doesn't mean you can listen to them at that point so I will attach the buttons after the loop is done.
require(["dojo/_base/array","dijit/form/ValidationTextBox",
"dijit/form/Button","dojo/dom","dojo/on","dojo/domReady!"], function(array,ValidationTextBox,Button,dom,on){
var getCardSummaryView = function(card) {
var html = "";
html += "</br>";
html += "<div>";
html += "<label>Product Name: " + card.Product.Name + "</label></br>";
html += "<button id='deleteCard" + card.Product.Id + "'>Delete</button>";
html += "</div>";
return html;
}
var objectvalue = {};
var arrayvalue = new Array();
objectvalue.Product = {};
objectvalue.Product.Name = "hello1";
objectvalue.Product.Id = "ThisisWhy1";
arrayvalue.push(objectvalue);
var test = {};
test.Product = {};
test.Product.Name = "hello2";
test.Product.Id = "ThisisWhy2";
arrayvalue.push(test);
var test2 = {};
test2.Product = {};
test2.Product.Name = "hello3";
test2.Product.Id = "ThisisWhy3";
arrayvalue.push(test2);
array.forEach(arrayvalue, function (item) {
var view = getCardSummaryView(item);
dom.byId("sideBar").innerHTML += "----------------"
dom.byId("sideBar").innerHTML += view;
var node = dom.byId("deleteCard" + item.Product.Id);
});
var myButton = new Button({
label: "Click me!",
onClick: function(){
alert("1");
}
}, "deleteCard" + "ThisisWhy1");
var myButton = new Button({
label: "Click me!",
onClick: function(){
alert("2");
}
}, "deleteCard" + "ThisisWhy2");
var myButton = new Button({
label: "Click me!",
onClick: function(){
alert("3");
}
}, "deleteCard" + "ThisisWhy3");
});
ofcourse you can loop through the buttons when creating them but just to elaborate i created three instances
Click HERE to see the working in jsfiddle.
Related
I added a delete function to a todo list app that i built. The delete function works; however, when I refresh the page all the items that i deleted come back. How can I remove the items permanently from the database?
$(function() {
// The taskHtml method takes in a JavaScript representation
// of the task and produces an HTML representation using
// <li> tags
function taskHtml(task) {
var checkedStatus = task.done ? "checked" : "";
var liClass = task.done ? "completed" : "";
var liElement = '<li id="listItem-' + task.id +'" class="' + liClass + '">' +
'<div class="view"><input class="toggle" type="checkbox"' +
" data-id='" + task.id + "'" +
checkedStatus +
'><label>' +
task.title +
// '<button class="deletebutton" type="button">Delete</button>' +
'</label></div></li>';
return liElement;
}
// toggleTask takes in an HTML representation of the
// an event that fires from an HTML representation of
// the toggle checkbox and performs an API request to toggle
// the value of the `done` field
function toggleTask(e) {
var itemId = $(e.target).data("id");
var doneValue = Boolean($(e.target).is(':checked'));
$.post("/tasks/" + itemId, {
_method: "PUT",
task: {
done: doneValue
}
}).success(function(data) {
var liHtml = taskHtml(data);
var $li = $("#listItem-" + data.id);
$li.replaceWith(liHtml);
$('.toggle').change(toggleTask);
} );
}
$.get("/tasks").success( function( data ) {
var htmlString = "";
$.each(data, function(index, task) {
htmlString += taskHtml(task);
});
var ulTodos = $('.todo-list');
ulTodos.html(htmlString);
$('.toggle').change(toggleTask);
});
$('#new-form').submit(function(event) {
event.preventDefault();
var textbox = $('.new-todo');
var payload = {
task: {
title: textbox.val()
}
};
$.post("/tasks", payload).success(function(data) {
var htmlString = taskHtml(data);
var ulTodos = $('.todo-list');
ulTodos.append(htmlString);
$('.toggle').click(toggleTask);
$('.new-todo').val('');
});
});
//////this section works
$("#deletebutton").on("click", function() {
$(".todo-list li.completed").remove()
///////this does not want to remove the item from the database
$.destroy("/tasks/" + itemId, {
_method: "destroy",
task: {
done: doneValue
}
});
});
$(function() {
// The taskHtml method takes in a JavaScript representation
// of the task and produces an HTML representation using
// <li> tags
function taskHtml(task) {
var checkedStatus = task.done ? "checked" : "";
var liClass = task.done ? "completed" : "";
var liElement = '<li id="listItem-' + task.id +'" class="' + liClass + '">' +
'<div class="view"><input class="toggle" type="checkbox"' +
" data-id='" + task.id + "'" +
checkedStatus +
'><label>' +
task.title +
// '<button class="deletebutton" type="button">Delete</button>' +
'</label></div></li>';
return liElement;
}
// toggleTask takes in an HTML representation of the
// an event that fires from an HTML representation of
// the toggle checkbox and performs an API request to toggle
// the value of the `done` field
function toggleTask(e) {
var itemId = $(e.target).data("id");
var doneValue = Boolean($(e.target).is(':checked'));
// still dont understand this
$.post("/tasks/" + itemId, {
_method: "PUT",
task: {
done: doneValue
}
}).success(function(data) {
var liHtml = taskHtml(data);
var $li = $("#listItem-" + data.id);
$li.replaceWith(liHtml);
$('.toggle').change(toggleTask);
} );
}
$.get("/tasks").success( function( data ) {
var htmlString = "";
$.each(data, function(index, task) {
htmlString += taskHtml(task);
});
var ulTodos = $('.todo-list');
ulTodos.html(htmlString);
$('.toggle').change(toggleTask);
});
$('#new-form').submit(function(event) {
event.preventDefault();
var textbox = $('.new-todo');
var payload = {
task: {
title: textbox.val()
}
};
$.post("/tasks", payload).success(function(data) {
var htmlString = taskHtml(data);
var ulTodos = $('.todo-list');
ulTodos.append(htmlString);
$('.toggle').click(toggleTask);
$('.new-todo').val('');
});
});
$("#deletebutton").on("click", function() {
$(".todo-list li.completed").remove()
var li_to_delete = $('.todo-list li.completed');
$.ajax({
type: 'DELETE',
url: "/tasks" + li_to_delete,
success: function(){
li_to_delete.remove();
}
});
});
});
i changed the code but im not sure how to properly extract the url.
In jquery, I am trying to get the text from a textarea tag, with the new lines as \n and not br tags. The problem is if I select it and get its val, the firefox debugger does not even show the \n or br. If I alert it, then I see there is two lines, but then if I insert it into the DOM, it removes all the new lines. I want it to keep its new lines.
I get it like this:
var handleSend = function(thread_id) {
var user = GLOBAL_DATA.user;
$(context).find("#message-form").unbind('submit').submit(function() {
var field = $(this).find("textarea");
runAJAXSerial($(this).serialize(), {
page : 'message/setmessage',
id : user['id'],
thread_id : thread_id
}, function(response) {
var user = GLOBAL_DATA.user;
var obj = {
user_id : user['id'],
message : field[0].value.replace(/<br\s*\/?>/mg,"\n"),
date_sent : getDate() + ' ' + getTime()
};
alert(obj.message);
cleanResponse(obj);
field.val("").focus();
displayMessages([obj], true);
}, function(data,status,xhr) {
});
return false;
});
};
function cleanResponse(response) {
if (Object.prototype.toString.call( response ) === '[object Array]') {
var i = 0, l = response.length;
for (i=0; i<l; i+=1) {
response[i] = cleanResponse(response[i]);
}
} else if (Object.prototype.toString.call( response ) === '[object Object]') {
for (var property in response) {
if (response.hasOwnProperty(property)) {
response[property] = cleanResponse(response[property]);
}
}
} else {
response = escapeHTML(response);
}
return response;
}
function escapeHTML(str) {
return $("<p/>").text(str).html();
}
var displayMessages = function(response, onBottom) {
var user = GLOBAL_DATA.user, i=0, l=response.length, acc = '';
for(i=0; i<l; 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 += '<img src="' + getImage(obj['user_id']) + '" align="right" class="message-image" />';
acc_temp += '<div>' + Autolinker.link(obj['message']) + '</div>';
acc_temp += '<br/>';
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);
};
var addMessage = function(html, onBottom) {
var list = $(context).find("#message-list");
if (onBottom) {
list.append(html);
scrollBot();
} else {
list.prepend(html);
}
};
displayMessages inserts the text into the DOM.
cleanResponse encodes the text so that the user can't execute scripts.
Does anyone know whats wrong?
Thanks
New lines in the DOM are treated like any other whitespace. You are getting the expected behaviour of adding the new lines.
If you want an new line to be rendered then you need to use a <br> element or modify the white-space CSS property.
I have created a mockup shopping basket, the quantity add's fine but the remove isn't working as it should. I have specificed in the remove method to splice at the location and to remove only 1 entry from the array but it seems to remove them all.
To reproduce the error just
Add 3 x Swede
Add 3 x Parsnip
Remove 1 x Swede
You can see the code via online IDE here https://codio.com/adam91holt/305CDE-Challenge-3
Here is the full JS code - the remove funtion is at the bottom
var shop = (function() {
var items = [];
var basketItems = [];
var count = 0;
return {
//Constructor to create the item
addItem: function(title, description, price) {
this.title = title;
this.description = description;
this.price = price;
this.id = count;
this.remove = (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
this.quantity = title
this.html = '<tr><td>' + this.title + '</td><td>' + this.description + '</td><td>' + this.price + '</td><td><button id="' + this.id + '">Add To Basket</button></td><tr>';
this.inBasket = '<tr id="' + this.remove + '"><td>' + this.title + '</td><td>' + this.price + '</td><td><div id="' + this.quantity + '">1</div>' + '</td><td><button id="' + this.remove + '"> Remove </button><tr>';
items.push(this);
count++;
},
//Sends new items to constructor
createItems: function() {
new this.addItem('Carrott', 'Lovely orange vegetable!', parseFloat(0.50).toFixed(2));
new this.addItem('Potato', 'Fresh baking potato.', parseFloat(0.75).toFixed(2));
new this.addItem('Brocolli', 'Green trees!', parseFloat(0.49).toFixed(2));
new this.addItem('Parsnip', 'Sweet tasting.', parseFloat(0.60).toFixed(2));
new this.addItem('Swede', 'Tasty fresh Swede.', parseFloat(1.00).toFixed(2));
console.log(items);
this.printHtml()
},
//Add's the html to the table from the item object
printHtml: function() {
var table = document.getElementById("output")
items.forEach(function(item) {
table.innerHTML += item.html;
})
this.listenerAdd()
},
//Creates a listener for adding to the basket
listenerAdd: function() {
items.forEach(function(item) {
document.getElementById(item.id).addEventListener("click", function() {
shop.addToBasket(item)
});
});
},
//Creates a listener for removing from the basket
listenerRemove: function() {
basketItems.forEach(function(item) {
document.getElementById(item.remove).addEventListener("click", function() {
shop.remove(item)
});
});
},
//Add's the item once the event listener has been triggered
addToBasket: function(item) {
basketItems.push(item);
this.total();
var basket = document.getElementById("basketitems");
var quantity = document.getElementById(item.quantity);
var howMany = this.checkQuantity(item);
if(howMany <= 1) {
basket.innerHTML += item.inBasket;
this.listenerRemove();
} else {
quantity.innerHTML = howMany;
}
},
//Checks basket to see if it is already there
checkQuantity: function(item) {
var searchTerm = item.title;
var howMany = 0;
for(var i = 0; basketItems.length > i; i++) {
if(basketItems[i].title === searchTerm) {
howMany++
}
}
return howMany;
},
//Calculates the running total
total: function() {
var total = 0
basketItems.forEach(function(items) {
var price = items.price;
total = total + parseFloat(price);
})
var totalHTML = document.getElementById("total");
totalHTML.innerHTML = '<b>Total = ' + parseFloat(total).toFixed(2) + '</b>';
},
//Allows you to remove items from the basket
remove: function(item) {
var where = basketItems.indexOf(item);
var quantity = document.getElementById(item.quantity);
basketItems.splice(where, 1);
this.total()
var howMany = this.checkQuantity(item);
if(howMany === 0) {
console.log(item.remove)
var row = document.getElementById(item.remove);
row.parentNode.removeChild(row);
} else {
quantity.innerHTML = howMany;
}
}
}
})();
function init() {
'use strict';
shop.createItems()
};
//On window load call init function
window.onload = init;
So in the event listener called listenerRemove you do a for each which results in basically registering the same event to the same click 5 times if the quantity is 5. Solution is to only register event for new items only so first change is get the item into the table using document.createElemenet
like this:
var tr = document.createElement('tr');
Give it your random ID
tr.id = item.remove;
Append the text from item.inBasket
tr.innerHTML = item.inBasket;
now append it to the table if it's new Item
basket.appendChild(tr);
Register event
this.listenerRemove(item);
In event register do a single registration rather than a foreach
listenerRemove: function(item) {
document.getElementById(item.remove).addEventListener("click", function() {
shop.remove(item)
});
},
And the rest see in the fiddle http://jsfiddle.net/guqno66d/
HTML:-
In the body tag I have used onload="variable2.init() ; variable1.init();".
JavaScript:-
var variable1 = {
rssUrl: 'http://feeds.feedburner.com/football-italia/pAjS',
init: function() {
this.getRSS();
},
getRSS: function() {
jQuery.getFeed({
url: variable1.rssUrl,
success: function showFeed(feed) {
variable1.parseRSS(feed);
}
});
},
parseRSS: function(feed) {
var main = '';
var posts = '';
var className = 'even';
var pst = {};
for (i = 0; i < feed.items.length; i++) {
pst = variable1.parsefootballitaliaRSS(feed.items[i]);
if (className == 'odd') {
className = 'even';
}
else {
className = 'odd';
}
var shorter = pst.story.replace(/<(?:.|\n)*?>/gm, '');
item_date = new Date(feed.items[i].updated);
main += '<div id="content1" class="post-main ' + className + '" onclick="mwl.setGroupTarget(\'#screens1\', \'#blog_posts1\', \'ui-show\', \'ui-hide\');mwl.setGroupTarget(\'#blog_posts1\', \'#post' + (i+1) + '\', \'ui-show\', \'ui-hide\');">';
main += '<b>' + pst.title.trunc(55, true) + '</b><br />' + shorter.trunc(30, true);
main += '<div class="datetime">' + item_date.getDateTime() + '</div></div>';
posts += '<div class="post-wrapper ui-hide" id="post' + (i+1) + '">';
posts += '<div class="post-title"><b>' + pst.title + '</b></div>';
posts += feed.items[i].description;
posts += '</div>';
}
jQuery('#main_screen1').html(main);
jQuery('#blog_posts1').html(posts);
},
parsefootballitaliaRSS: function(item) {
var match = item.description.match('src="([^"]+)"');
var part = item.description.split('<font size="-1">');
var arr = {
title: item.title,
link: item.link,
image: match,
site_title: item.title,
story: item.description
};
return arr;
}
};
var variable2 = {
weatherRSS: 'http://feeds.feedburner.com/go/ELkW',
init: function() {
this.getWeatherRSS();
},
getWeatherRSS: function() {
jQuery.getFeed({
url: variable2.weatherRSS,
success: function showFeed(feed) {
variable2.parseWeather(feed);
}
});
},
parseWeather: function(feed) {
var main = '';
var posts = '';
var className = 'even';
var pst = {};
for (i = 0; i < feed.items.length; i++) {
pst = variable2.parsegoRSS(feed.items[i]);
if (className == 'odd') {
className = 'even';
}
else {
className = 'odd';
}
var shorter = pst.story.replace(/<(?:.|\n)*?>/gm, '');
item_date = new Date(feed.items[i].updated);
main += '<div id="content2" class="post-main ' + className + '" onclick="mwl.setGroupTarget(\'#screens2\', \'#blog_posts2\', \'ui-show\', \'ui-hide\');mwl.setGroupTarget(\'#blog_posts2\', \'#post' + (i+1) + '\', \'ui-show\', \'ui-hide\');">';
main += '<b>' + pst.title.trunc(55, true) + '</b><br />' + shorter.trunc(30, true);
main += '<div class="datetime">' + item_date.getDateTime() + '</div></div>';
posts += '<div class="post-wrapper ui-hide" id="post' + (i+1) + '">';
posts += '<div class="post-title"><b>' + pst.title + '</b></div>';
posts += feed.items[i].description;
posts += '</div>';
}
jQuery('#main_screen2').html(main);
jQuery('#blog_posts2').html(posts);
},
parsegoRSS: function(item) {
var match = item.description.match('src="([^"]+)"');
var part = item.description.split('<font size="-1">');
var arr = {
title: item.title,
link: item.link,
image: match,
site_title: item.title,
story: item.description
};
return arr;
}
};
When I run the program it only reads one of the variables i.e. either 1 or 2.
How can I correct them to read both the variables?
Use this.
<script type="text/javascript">
window.onload = function() {
variable1.init();
variable2.init();
}
</script>
Try this
<body onload="callFunctions()">
JS-
function callFunctions()
{
variable1.init();
variable2.init();
}
Update-
Also
there are other different ways to call multiple functions on page load
Hope it hepls you.
Buildgames returns rows:
<a>....</a>
<a>....</a>
When I click on each a the Buildcar_s function returns all the data inside an alert.
Instead of this alert I want to put all the results in a div under each a, so it would look like:
<a>.....clicked ...</a>
<div>....
...
</div>
<a>....not clicked...</a>
<a>....not clicked...</a>
<a>....not clicked...</a>
How can we put a div only under the a which was clicked?
function Buildcar_s(items) {
var div = $('<div/>');
$.each(items, function() {
var car_ = this.car_;
$('<a>' + this.car_ + '----' + this.Names + '---' + '</a>').click(function() {
_Services.invoke({
method: 'GetgamesRows',
data: {
car_Number: car_
},
success: function(car_s) {
var div = Buildgames(car_s);
$(div).insertAfter($a);
}
});
}).appendTo(div);
$('<br/>').appendTo(div);
});
$("#leftRows").append(div);
}
function Buildgames(items) {
var place = '<div>';
$.each(items, function() {
place += 'mmmmmm<br/>';
});
place += '</div>';
return place;
}
Try this, relevant changes have been commented:
function Buildcar_s(items) {
var div = $('<div/>');
$.each(items, function() {
var car_ = this.car_;
$('<a>' + this.car_ + '----' + this.Names + '---' + '</a>').click(function() {
var $a = this;
_Services.invoke({
method: 'GetgamesRows',
data: {
car_Number: car_
},
success: function(car_s) {
var div = Buildgames(car_s);
// this inserts the HTML generated from the function,
// under the A element which was clicked on.
$(div).insertAfter($a);
}
});
}).appendTo(div);
$('<br/>').appendTo(div);
});
$("#leftRows").append(div);
}
function Buildgames(items) {
var place = '<div>';
$.each(items, function() {
place += '<div style="float: right;"> ' + this.CITY + ' ' + '</div><BR />' + +'<br/><br/>';
});
place += '</div>';
return place; // returns the string created, as opposed to alerting it.
}