Problem with jquery - javascript

I creating jquery code to generate specific html-blocks that contains html-controls (e.g. textbox, textarea, button) with two buttons - add new block and delete current block:
$(document).ready(function () {
// Constants
var SEPARATOR = "`";
var SEPARATOR_START = "<span class='Hidden'>";
var SEPARATOR_END = "</span>";
var SEPARATOR_BLOCK = SEPARATOR_START + SEPARATOR + SEPARATOR_END;
var CONTAINER = "#weContainer";
// Initialize container
InitializeDataContainer(CONTAINER);
// Buttons events
$(".AddBlock").click(function () {
AddBlock(CONTAINER);
});
$(".DeleteBlock").click(function () {
DeleteBlock(CONTAINER, GetParentId(this));
});
// Functions
function GetParentId(container) {
var id = ($(container).parent().attr("id")).replace(new RegExp("_", 'g'), "");
return id;
}
function Template() {
var uniqueId = Math.random() * 10000000;
var template = "<div class='weBlock' id='_" + uniqueId + "_'>";
template += "<input type='button' value='add' class=\"AddBlock\" />";
template += "<input type='button' value='del' class=\"DeleteBlock\" />";
template += "<br/>";
template += "<input type='text' class='weStartDate weTextbox' />";
template += " ";
template += "<input type='text' class='weEndDate weTextbox' />";
template += "<br/>";
template += "<input type='text' class='weCompany weTextbox' />";
template += " ";
template += "<input type='text' class='weJobTitle weTextbox' />";
template += "<br/>";
template += "<input type='text' class='weClients weTextbox' />";
template += " ";
template += "<input type='text' class='weProjectName weTextbox' />";
template += "<br/>";
template += "<textarea type='text' rows='4' cols='40' class='weProjectDesc weTextarea'></textarea>";
template += "<br/>";
template += "<textarea type='text' rows='6' cols='40' class='weActivities weTextarea'></textarea>";
template += "<br/>";
template += "<textarea type='text' rows='4' cols='40' class='weToolsTech weTextarea'></textarea>";
template += "</div>";
template += SEPARATOR_BLOCK;
return template;
}
function GetIdFromTemplate(template) {
var array = template.split('_');
return array[1];
}
function AddBlock(container) {
$(container).append(Template());
}
function DeleteBlock(container, id) {
var content = $(container).html();
content = content.replace(new RegExp("\<span class='Hidden'\>", "g"), "")
.replace(new RegExp("\</span\>", "g"), "");
var blocks = content.split(SEPARATOR);
content = "";
var index;
for (var i = 0; i < blocks.length; i++) {
if (GetIdFromTemplate(blocks[i]) != id && !IsNullOrEmpty(blocks[i])) {
content += blocks[i] + SEPARATOR_BLOCK;
}
else {
index = i;
}
}
$(container).html(content);
}
function IsNullOrEmpty(string) {
if (string == null || string == 'undefined' || string.length == 0) {
return true;
}
else {
return false;
}
}
function InitializeDataContainer(container) {
$(container).html(Template());
}
});
For the first time (when page load) i created first block:
function InitializeDataContainer(container) {
$(container).html(Template());
}
My problem is next - buttons Add and Delete work only for this first html-block that i created when page load, but if i add new blocks in page using Add button (from this first block that works) then buttons Add and Delete from this new blocks doesn't work!
Sorry for may be not good code, im not javascript engineer:)

Use the .live() instead:
$(".AddBlock").live("click", function () {
AddBlock(CONTAINER);
});
And same for the other class - the .click() is "static" only for the elements that exists in the time of calling it, while .live() should work for any existing or future elements.

Your jQuery code adds event handlers to the Add/Delete buttons you create uses click to do so:
$(".AddBlock").click(function () {
AddBlock(CONTAINER);
});
This only affects HTML elements that are already in the page.
One solution would be to change it to
$(".AddBlock").live('click', function () {
AddBlock(CONTAINER);
});
to make it also work for elements that get added to the page later.
Another solution would be to manually add the click event handlers to any elements you add to the page dynamically:
function AddBlock(container) {
var $template = $(Template());
$(container).append($template);
$template.find(".AddBlock").click, function () {
AddBlock(CONTAINER);
});
$template.find(".DeleteBlock").click, function () {
DeleteBlock(CONTAINER, GetParentId(this));
});
}

Related

Store Values of Checkboxes in Array in Google Apps Script

I have a dynamic array as such:
var PartnerEmailList = [one#email.com, two#email.com, three#email.com];
The following function creates a table that is displayed in a showModalDialog window.
function makeTableHTML() {
var PartnerEmailList = [one#email.com, two#email.com, three#email.com];
var result = "<table border=0>";
result += "<tr><td style=\"text-align:center\"><input type=\"checkbox\" name =" + PartnerEmailList[0] + " value =" + PartnerEmailList[0] + " checked></input></td>";
result += "<td style=\"vertical-align:text-middle\">" + PartnerEmailList[0] + "</td></tr>";
for(var i=1; i<PartnerEmailList.length; i++) {
result += "<tr><td style=\"text-align:center\"><input type=\"checkbox\" unchecked></input></td>";
result += "<td style=\"vertical-align:text-middle\">" + PartnerEmailList[i] + "</td></tr>";
}
result += "</table>";
result += "<input type=\"submit\" value=\"Submit\" class=\"action\" onclick=\"form_data()\">"
result += "<input type=\"button\" value=\"Close\" onclick=\"google.script.host.close()\">"
return result;
}
The user clicks a button within Google Sheets that runs the following script. This script pops up a ModalDialog window where the user can check which emails they want to send this product to.
function SelectEmails(){
var ui = SpreadsheetApp.getUi();
var result = makeTableHTML();
var bccSend = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('main_gen').getRange(2,2).getValue();
if(bccSend === ''){
//Call the HTML file and set the width and height
var html = HtmlService.createHtmlOutput(result)
.setWidth(450)
.setHeight(300);
//Display the dialog
var dialog = ui.showModalDialog(html, "Select the intended recipients of this briefing.");
}
}
I need to write a function that looks through all the checkboxes (they are all assigned a value within the html code) and stores the values of each one that is checked in an array. I will be calling this array in a different function to actually send out the email.
There may be a much better way to go about this, but this is what I have come up with so far. Any help would be much appreciated! Thanks!

How can I make this click counter work properly?

I'm making a Marvel API project. I added a Like button so it could count the likes, but everytime I click any like button the only counter adding numbers is the first one. Can anyone tell me how I do this properly?
The problem is because the ID is being made by a for, so how could I solve this?
This is my JS code (on the js file of my project) :
success: function(data)
{
footer.innerHTML = data.attributionHTML;
var string = "";
string += "<div class='row'>";
for (var i = 0; i < data.data.results.length; i++)
{
var element = data.data.results[i];
string += '<div class="col-md-3" align="center">';
string += "<img src='" + element.thumbnail.path + "/portrait_fantastic." + element.thumbnail.extension + "'/>";
string += '<button class="btn btn-success" onClick="testo()"><i class="fas fa-thumbs-up"></i> | <a id="likes">0</a></button>';
string += "<h3>" + element.title + "</h3>";
string += "</div>";
if ((i + 1) % 4 == 0)
{
string += "</div>";
string += "<div class='row'>";
}
}
marvelContainer.innerHTML = string;
}
And this is my onclick function (It is on my html file because it wont work on my js file)
<script>
var likes=0;
function testo()
{
likes += 1;
document.getElementById("likes").innerHTML = likes;
}
</script>
That is because all your buttons are being generated with the same id="likes" and then you are changing the HTML with document.getElementById("likes").innerHTML = likes;
for your code to work properly you will need to use a different approach, maybe adding a data-* attribute to your buttons and then change the likes by the data-* atribute using .getAttribute('data-id-something').innerHTML instead of document.getElementById("likes").innerHTML.
Or even better in this case you can give the buttons a class name and handle it with: document.getElementsByClassName("like-btn")
You can check the last option in this example:
var init = function(data){
var string ="";
string += "<div class='row'>";
for(var i = 0; i<4; i++)
{
// var element = data.data.results[i];
string += '<div class="col-md-3" align="center">';
string += "<img src='/portrait_fantastic.jgeg'/>";
string += '<button class="btn btn-success" onClick="testo('+i+')"><i class="fas fa-thumbs-up"></i> | <span class="like-btn">0</span></button>';
string += "<h3>Element title</h3>";
string += "</div>";
if((i+1) % 4 ==0)
{
string += "</div>";
string += "<div class='row'>";
}
}
document.getElementById("marvelContainer").innerHTML = string;
}
init();
<script>
var likes=0;
function testo(id) {
var btn = document.getElementsByClassName("like-btn");
likes = parseFloat(btn[id].innerHTML);
likes += 1;
btn[id].innerHTML = likes;
}
</script>
<div id="marvelContainer"></div>
I hope it will help you...
Gave the buttons a class, as that is what is going to be clicked.
Changed the link element to a span. Having a link in a button doesn't make much sense, as you can't "not" click the button and click the link.
Removed the inline onclick for the link and added an event listener logically on all the buttons.
The click logic finds the nested span in the button
It takes the data attribute on the span, turns it into an integer, and increments it
It then updates the data attribute value for the next click
And finally it updates the visible text that the user can see
EDIT
Changed it to bind the click event listener on the span as well and stop propagation on the click event. Actually clicking the span was causing the click event to register for the span, and not the button.
// fake out some data for the element generation
var data = { data: {
results: [
{ thumbnail: { path: '/path1', extension: 'jpg', title: 'Element1' } }
,{ thumbnail: { path: '/path2', extension: 'png', title: 'Element2' } }
,{ thumbnail: { path: '/path3', extension: 'gif', title: 'Element3' } }
]
} };
// fake out the container the elements are built to
var marvelContainer = document.querySelector('#container');
var string = "<div class='row'>";
for (var i = 0; i < data.data.results.length; i++) {
var element = data.data.results[i];
string += '<div class="col-md-3" align="center">';
string += "<img src='" + element.thumbnail.path + "/portrait_fantastic." + element.thumbnail.extension + "'/>";
// put a class on the button
// also removed the id and inline onclick
// change the id on the link to a class
// also initialized the data-likes on the link to zero
string += '<button class="btn btn-success likes-button"><i class="fas fa-thumbs-up"></i> | <span class="likes" data-likes="0">0</span></button>';
string += "<h3>" + element.title + "</h3>";
string += "</div>";
if ((i + 1) % 4 == 0) {
string += "</div>";
string += "<div class='row'>";
}
}
marvelContainer.innerHTML = string;
document.querySelectorAll('.likes-button, .likes').forEach(function(likeButton){
likeButton.addEventListener('click', incrementLikes);
});
function incrementLikes (e) {
e.stopPropagation();
// find the inner likes element of the button
var likes = e.target.querySelector('.likes') || e.target;
// increment the likes
var incrementedLikes = parseInt(likes.dataset.likes) + 1;
// update the data attribute for next click, and update the text
likes.dataset.likes = incrementedLikes.toString();
likes.innerText = incrementedLikes;
}
<div id="container">
</div>

jquery added html code not worked

I started new project and I use jquery to add content to article
when I create a slider with this code:
$(".inserttabtext1").click(function () {
var count = parseInt($(".firsttabtextcount").attr("name"), 10);
var name = parseInt($(this).attr("name"));
var id = "#" + name;
var idi,idt,content,idic,idtc;
content = "<div class='short-tabs'><ul>";
for (var i = 1; i <= count; i++)
{
idi = "#ftti" + i;
idic = $(idi).val();
if (i == 1)
{
content += "<li class='active'><a href='#'> " + i + idic + "</a></li>";
}
else
{
content += "<li><a href='#'> "+ i + idic +"</a></li>";
}
}
content += "</ul>";
for (var i = 1; i <= count; i++)
{
if (i==1)
{
content += "<div class='active'>";
}
else
{
content += "<div>";
}
idt = "#fttt" +i;
idtc = $(idt).val();
content += "<p class='text-go-center'>"+idtc+"</p></div>";
}
content += "</div>";
$(id).html(content);
});
and put them into html code my text slider not worked
but when I put manual html code in my page it work
I use these code for copy my html code
$(id).html(content);
$(id).append(content);
where is my wrong?
create a function and put your slider codes inside it, then call it in $(document).ready, and call it again after adding html
$(document).ready(function(){
Init();
});
function Init(){
//Call your slide function here
}
call Init after Adding Html
$(id).html(content);
$(id).append(content);
Init();

parse HTMLElmentObject with innerHTML in javascript

I am building a cat clicker game. Where I Have five cat and each one has click function which increase count on every click.
I have created a DOM from javascript function, I have create image from document.create method so that I can attached event to it. So my javascript code contains both pure HTML and HTMLElementObj. fiddle.
But innerHTML is not paring the element which is creating by the document.createElement
function fac(name) {
this.name = name;
this.count = 0;
}
var cats = ['cat1', 'cat2', 'cat3', 'cat4', 'cat5']
function $(name) {
return document.querySelector(name);
}
var html = "";
for (var i = 0; i < cats.length; i++) {
var cat = new fac(cats[i])
html += "<div>";
html += "<div>" + cat.name + "</div>";
var elem = document.createElement('img');
elem.src = 'https://c2.staticflickr.com/2/1126/625069434_db86b67df8_n.jpg';
html += elem;
html += "<div class='count " + i + "'></div>";
html += "</div>";
elem.addEventListener('click', function() {
$('.count' + i).innerText = ++cat.count;
}, false);
$('#getClicked').innerHTML = html
}
You are mixing strings and dom elements and that won't work. Just do everything as strings
html += "<div>";
html += "<div>" + cat.name + "</div>";
var elem = "<img src='https://c2.staticflickr.com/2/1126/625069434_db86b67df8_n.jpg'>";
html += elem;
html += "<div class='count " + i + "'></div>";
or as dom elements (a bit more learning needed to start with but better in the long run)

JQuery help, How to Hide all button in JQuery

I'm trying to make a request/reply section in my project.
I want to achieve these functionality in that code (that I'm not able to implement; so guys please help me out):
1> When user click on reply button; other reply area(text-area +button) should be hide (means at a time only one reply area should be visible to the user).
2> when user click on reply button text-area will focus and page will slide down (suppose user reply 10 comment focus will automatically set to the 10 number text area and page will slide down to that position accordingly).
Here is my so far code guys:
//method call on the click of reply link.
function linkReply_Clicked(issueId) {
Id = issueId;
textId = "text_" + issueId + count;
btnReply = "btnReply_" + issueId + count;
btnCancel = "btnCancel_" + issueId + count;
var textareasArray = document.getElementsByTagName("textarea");
var btnArray = document.getElementsByTagName("input");
for (i = 0; i < textareasArray.length; i++) {
textareasArray[i].style.display = "none";
btnArray[i].style.display = "none";
}
var str = "<table cellpadding='3' cellspacing='0' width='58%'>";
str += "<tr><td valign='top' align='left'>";
str += "<textarea id=" + textId + " rows='5' cols='60'></textarea>";
str += "</td></tr>";
str += "<tr><td valign='top' align='right'>";
str += "<input id=" + btnReply + " type='button' onclick='btnReply_Clicked(Id ,textId)' value='Reply' /> ";
str += "<input id=" + btnCancel + " type='button' onclick='btnCancel_Clicked(Id ,textId)' value='Cancel' /> ";
str += "</td></tr>";
str += "</table>";
document.getElementById("divOuter_" + issueId).innerHTML = str;
$("#" + textId + "").focus();
}
// submit user reply and try to hide that reply area.
function btnReply_Clicked(issueId, textID) {
var comment = document.getElementById(textID).value;
if (comment != '') {
$.getJSON("/Issue/SaveComment", { IssueId: issueId, Comment: comment }, null);
$("#text_" + issueId + count).hide();
$("#btnReply_" + issueId + count).hide();
$("#btnCancel_" + issueId + count).hide();
document.getElementById(textID).value = '';
count = count + 1;
}
}
// cancel user reply and try to hide that reply area.
function btnCancel_Clicked(issueId, textId) {
$("#text_" + issueId + count).hide();
$("#btnReply_" + issueId + count).hide();
$("#btnCancel_" + issueId + count).hide();
document.getElementById(textId).value = '';
count = count + 1;
}
I changed a bit of this because you can do it much easier since you're already using jQuery :)
Go here for the demo version
You can replace all of your posted code with this:
function linkReply_Clicked(issueId) {
$(".replyTable").hide();
var tbl = $("<table class='replyTable' cellpadding='3' cellspacing='0' width='58%'></table>");
tbl.append("<tr><td valign='top' align='left'><textarea rows='5' cols='60'></textarea></td></tr>");
tbl.append("<tr><td valign='top' align='right'><input type='button' class='reply' value='Reply' /> <input type='button' class='cancel' value='Cancel' /> </td></tr>");
tbl.find(".reply").click(function() {
var comment = $(this).closest("table").find("textarea").val();
if (comment != '') {
$.getJSON("/Issue/SaveComment", { IssueId: issueId, Comment: comment }, null);
$(this).closest("div").empty();
}
}).siblings(".cancel").click(function() {
$(this).closest("div").empty();
});
var div = $("#divOuter_" + issueId).empty().append(tbl);
$('html, body').animate({ scrollTop: $(div).offset().top }, 500,
function() { div.find("textarea").focus(); });
}
This does the following things differently with the slide effect & the hiding and scrolling from the question:
Click handlers for reply/cancel buttons are now in-line, no need for extra functions
The inputs no longer have IDs you need to track, it just finds them relatively
Table has a class replyTable so it all old ones can be hidden quickly
Inputs have classes to find them easier (to bind the click handlers)
No more count, no need :)
Animates the body, does a quick scroll effect to the location and focuses the text area
Removes old tables to cleanup

Categories