I am building a form, where user can ADD or REMOVE rows dynamically. I have built jQuery Functions to accomplish this however I am losing some elements in the process and I can't figure out why.
HTML Snippet
<div class="options" id="options">
<div class="item1" id="item1">
<div class="left_wrap">
<ul>
<li class="col_id b-bottom"></li>
<li class="hazard_header"><h3>Hazard</h3></li>
<li class="hazard_input b-bottom"></li>
<li class="con_header b-bottom"><h3>Controls</h3></li>
<li class="cat_header"><h3>Consequence Category</h3></li>
<li class="cat_options"></li>
</ul>
</div>
<div class="right_wrap">
</div>
<div class="controls">
<div class="addRow" onclick="addRow()"><i class="fa fa-plus"></i>Add Row</div>
<div class="deleteRow" onclick="deleteRow('#item1')"><i class="fa fa-times"></i> Delete Row</div>
</div>
</div><!-- End Item -->
</div> <!-- End Options Wrap -->
jQuery
var count = 1;
var wrap;
var item;
function addRow(){
count++;
var $newElement = $(item);
$newElement.find("li.col_id").text(count);
// Doesn't work
$newElement.find(".item1").removeClass("item1").addClass("item"+count);
// Remove ID item1 make it (item+count)
// Change deleteRow('#item1') to deleteRow('#item2')
$($newElement).appendTo(".options");
};
$(document).ready(function(){
wrap = $(".options").html();
item = wrap;
id = $("div.item1");
id.find("li.col_id").text("1");
});
I have commented out parts inside the addRow that I am having problems with. Wired thing is when I display my (item) inside .ready it shows me wrap () however when I do it inside addRow it doesn't show it anymore.
I have been stuck on this for few hours and have tried few different ways to do this however I keep coming up short.
When I click Add Row it does work however I can never change the class and id for the wrap.
I have updated your Code.
$newElement is already the main DIV that you want to update with new ID and Class.
var count = 1;
var wrap;
var item;
function addRow(){
count++;
var $newElement = $(item);
$newElement.find("li.col_id").text(count);
// Remove previous class and Add new Class
$newElement.attr('class','').addClass("item"+count);
// Update the ID
$newElement.attr('id',"item"+count);
// Update the onlick event with new Item ID
$newElement.find('.deleteRow').attr('onclick','deleteRow("#'+"item"+count+'")');
// Remove ID item1 make it (item+count)
// Change deleteRow('#item1') to deleteRow('#item2')
$($newElement).appendTo(".options");
};
$(document).ready(function(){
wrap = $(".options").html();
item = wrap;
id = $("div.item1");
id.find("li.col_id").text("1");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="options" id="options">
<div class="item1" id="item1">
<div class="left_wrap">
<ul>
<li class="col_id b-bottom"></li>
<li class="hazard_header"><h3>Hazard</h3></li>
<li class="hazard_input b-bottom"></li>
<li class="con_header b-bottom"><h3>Controls</h3></li>
<li class="cat_header"><h3>Consequence Category</h3></li>
<li class="cat_options"></li>
</ul>
</div>
<div class="right_wrap">
</div>
<div class="controls">
<div class="addRow" onclick="addRow()"><i class="fa fa-plus"></i>Add Row</div>
<div class="deleteRow" onclick="deleteRow('#item1')"><i class="fa fa-times"></i> Delete Row</div>
</div>
</div><!-- End Item -->
</div> <!-- End Options Wrap -->
Related
I'm making a website that includes carousels and buttons. When you click the buttons it moves the carousel to the left or right to see more or previous content. I made it at first by creating two functions, one for the button that goes back and one for the button that goes forward. It worked, but I realized that I needed to make it for All of the buttons since I had multiple carousels.
var nextButton = document.querySelectorAll('.button-forward');
var backButton = document.querySelectorAll('.button-back');
nextButton.addEventListener('click', function() {
itemContainer.style.transform = 'translateX(-40%)';
});
backButton.addEventListener('click', function() {
itemContainer.style.transform = 'translateX(10%)';
});
I tried storing all the forward and backward buttons with document.querySelectorAll and gave them a forEach method where in it is the event listener for them. The other two carousel buttons still weren't working, I also tried making them an array to see if it would help, but it didn't change anything. In summary I want to make it where I can give the event listener to all of the pairs of buttons instead of just one. Could you guys help me? If you need a better description please tell me!
var nextButton = document.querySelectorAll('.button-forward');
var backButton = document.querySelectorAll('.button-back');
nextButton.forEach(button => {
button.addEventListener('click', nextButton => {
itemContainer.style.transform = 'translateX(-40%)';
})
})
backButton.forEach(button => {
button.addEventListener('click', backButton => {
itemContainer.style.transform = 'translateX(10%)';
})
})
Here's my HTML structure of the carousel for those who want to know:
I used the main element keep the parts of my carousel together, inside it is the visible_items div that only shows the items that are in it with overflow: scroll in CSS. Inside of that os the item_container which just contains the items. The ion-icons or buttons are at the top and bottom of the main element, and when you click them they make the item_container translate left or right making the items shown in the visible_items div change.
<ion-icon name="chevron-back-outline" class="button-back"></ion-icon>
<main>
<h1>Poular Shoes</h1>
<div class="visible_items">
<div class="item_container">
<div class="items">
</div>
<div class="items">
</div>
<div class="items">
</div>
<div class="items">
</div>
<div class="items">
</div>
<div class="items">
</div>
<div class="items">
</div>
<div class="items">
</div>
</div>
</div>
<ion-icon name="chevron-forward-outline" class="button-forward"></ion-icon>
</main>
The procedure is correct, however I am afraid you are applying the transformation always to the same "itemContainer" element. This should in fact point to the element related to the button pair you assign during that iteration.
We then need to fetch all the carousels via querySelectorAll; each will have element containers and their buttons as children. In this case you have a guaranteed order and only one array to scroll through.
Example:
document.body.querySelectorAll(".carousels").forEach((c) => {
const container = c.querySelector(".container")
c.querySelector(".next")
.addEventListener("click",
() => container.style...)
c.querySelector(".back")
.addEventListener("click",
() => container.style...)
})
I would recommend that you modify your html code as follows:
<!-- Move this inside the carousel div -->
<ion-icon name="chevron-back-outline" class="button-back"></ion-icon>
<!-- This is not a good tag to create many carousel divs -->
<!-- I will use something like <div class="carousel"> -->
<main>
<h1>Poular Shoes</h1>
<div class="visible_items">
<div class="item_container">
<div class="items">
</div>
<div class="items">
</div>
<div class="items">
</div>
<div class="items">
</div>
<div class="items">
</div>
<div class="items">
</div>
<div class="items">
</div>
<div class="items">
</div>
</div>
</div>
<ion-icon name="chevron-forward-outline" class="button-forward"></ion-icon>
</main>
I'll leave you a snippet to start with:
// get all carousels in the page
const carousels = document.body.querySelectorAll(".carousel");
// scan each carousel and assign events to children
carousels.forEach((carousel) => {
// get item_container
const itemContainer = carousel.querySelector(".item_container");
// assign event to button-back
carousel.querySelector(".button-back").addEventListener('click', () => {
itemContainer.style.transform = 'translateX(-40%)';
});
// assign event to button-forward
carousel.querySelector(".button-forward").addEventListener('click', () => {
itemContainer.style.transform = 'translateX(10%)';
});
});
<!-- Changed -->
<div class="carousel">
<!-- Moved -->
<ion-icon name="chevron-back-outline" class="button-back"></ion-icon>
<h1>Poular Shoes</h1>
<div class="visible_items">
<div class="item_container">
<div class="items">
</div>
<div class="items">
</div>
<div class="items">
</div>
<div class="items">
</div>
<div class="items">
</div>
<div class="items">
</div>
<div class="items">
</div>
<div class="items">
</div>
</div>
</div>
<ion-icon name="chevron-forward-outline" class="button-forward"></ion-icon>
<!-- Changed -->
</div>
I am using JQuery SlideUp and slideDown methods to show/hide panels. How can load or display the first record Contact information as a default?
Right now it loads blank because i set the panel display:none:
<div class="panel rpspanel panel-default" id="#item.ID" style="display: none"> otherwise it loads all if i have multiple results.
Need help to load the first one when the page loads. And the rest on click event which working perfect.
Left Panel:
Pass the item id (or any unique value) to the li in data-id attribute
<ul id="treeview">
#foreach (var item in rpInfo)
{
<li data-expanded="true" class="panel-handler" data-id="#item.id">
<i class="fa fa-check-circle"></i>#item.PartyName
<ul>
<li data-expanded="true"> <i class="fas fa-check-circle"></i> #item.ContactName </li>
</ul>
</li>
}
</ul>
Right Panel:
id attribute to all panels. the same id which i have passed in the left panel.
#foreach (var item in rpInfo)
{
var DeleteModal = "#myModal" + item.ID;
var mid = "myModal" + item.ID;
<div class="panel rpspanel panel-default" id="#item.ID" style="display: none">
Contact Information</h4>
</div>
<div class="panel-body">
<div class="card card-understated">
<div class="card-heading">
<h4>#(Localizer["Contact Preview "])</h4>
</div>
<div class="card-body">
<p>
#item.ContactName<br>
#item.ContactTitle<br>
#item.PartyName<br>
#item.AddressLine1<br />
#item.City, #item.State #item.Country
</p>
</div>
</div>
</div>
</div>
}
Jquery script:
On on left panel on li click get the data-id attribute value.
Hide all panels .
Show the panel with the specified id attribute.
$(document).ready(function() {
$(".panel-handler").click(function() {
let id = $(this).data("id");
$(".rpspanel").slideUp();
$("#" +id).slideDown();
});
});
Make a separate function for the slideDown() functionality based on id, and pass id of the first .panel-handler on load of document:
$(document).ready(function() {
$(".panel-handler").click(function() {
showInfo($(this).data("id"));
});
function showInfo(id){
$(".rpspanel").slideUp();
$("#" +id).slideDown();
}
// For first time
showInfo($(".panel-handler").eq(0).data("id"))
});
This code is used to remove a cart-item from a partial view.
$(document).on('click', '.RemoveLink', (function (e) {
e.preventDefault();
var recordToDelete = $(this).attr("data-id");
var itemID = $(this).attr("data-itemid");
if (recordToDelete != '') {
$.post("/ShoppingCart/RemoveFromCart", { "id": recordToDelete, "itemID": itemID },
function () {
$('.container-cart').load('#Url.Action("cartDropDown","ShoppingCart")', function () {
$('.cart-dropdown').css('display', 'inline-block');
}
);
});
}
}));
This works well for the first iteration but from the second iteration on-wards, every click of a remove of an item is resulting in deletion of 2 items of a kind. Suppose we had 4 items of pencils and 8 items of pens. Clicking delete pencil button once will result in deletion of 2 pencils and vice versa.
This is probably because of the logic used. Following is the html that is rendered when $('.container-cart').load('#Url.Action("cartDropDown","ShoppingCart")' executes:
#model OnlineStore.ViewModels.ShoppingCartViewModel
<div class="container-cart">
#if (Model.ItemCount == 0)
{
<div>
<span>
There are no items in your cart. Continue shopping.
</span>
</div>
}
else
{
<ul class="cart-dropdown">
<li>
<div class="cart-items cart-caption">
<ul>
#foreach (var i in Model.CartItems)
{
<li id="list-item-#i.item.ItemID">
<div class="container-fluid item-wrap" style="position: relative">
<div class="item-remove">
<a href="#" class="RemoveLink"
data-id="#i.RecordID" data-itemid="#i.item.ItemID">
x
</a>
</div>
<div class="col-md-2 item-img">
<div class="row-cart">
<img alt="" id="cartImg" height="71" width="75" src="#i.item.ImageUrl">
</div>
</div>
<div class="col-md-5 item-info">
<div class="row-cart">
<div class="brand-name">
<a href="#" class="brandName">
#i.item.BrandName
</a>
</div>
<div class="product-name">
<a href="#" class="productName">
#i.item.ItemName
</a>
</div>
<div class="product-qty">
<p class="productQTY" id="item-count-#i.item.ItemID">
#i.Count x #i.item.ItemPrice
</p>
</div>
</div>
</div>
<div class="col-md-5 price-info">
<div class="row-cart" style="margin-top: 10px">
<div class="col-md-6">
<div class="row-mrp">
<span class="cartItemPrice" id="item-total-#i.item.ItemID">
Rs #(#i.Count * #i.item.ItemPrice)
</span>
</div>
</div>
</div>
</div>
</div>
</li>
}
</ul>
</div>
</li>
<li class="clearfix">
<div class="col-md-6">
<div class="row-cart sub-cost" style="background: #fff; margin-left: -10px; margin-right: 0">
<p>
Sub Total :
<span style="float: right">
Rs
<span class="ng-binding"></span>
</span>
</p>
<p>
Delivery Charge :
<span qa="delChargeMB" style="float: right">Free</span>
</p>
</div>
<div class="row-cart cart-chkout-btn">
<button type="button">View Basket & Checkout</button>
</div>
</div>
</li>
</ul>
}
</div>
This html is the partial view that is initially rendered when user clicks a button to view the cart-items. So when user clicks on 'remove an item' button on this partial view, an ajax call is sent to server to remove an item from the cart-items and on success, load the UI again by rendering this partial view once again with new values from the database.
All this is working fine for the first iteration of the deletion of an item from the cart-item list. But when I'm deleting an item again as a second deletion, code is running twice. I'm guessing this is because <div class="container-cart"> is rendered twice on the page as after the first deletion, I can see it on the live DOM inside the browser that <div class="container-cart"> is encolsed inside another <div class="container-cart"> and then the normal elements are rendered in sequence. I'm guessing maybe that's why javaScript is rendered twice or running twice.
Please suggest what you think about it and help me resolve it.
Thanks in advance
After deletion of an item try to use location.reload(); instead of hitting the MVC action method again!
In the Index file I have these divs which I note by IDs, let's say there are 3 of these:
<div class="col-sm-6 col-md-4 col-lg-3 grid-item" id="one">
<div class="well">
<a href="http://" target="_blank">
<img class="class" src="img/pic.jpg" alt=""/>
</a>
<p></p>
<nav>
<div class="anim-icons">
<ul>
<li>
<a href="#">
<img src="" alt="">
</a>
</li>
</ul>
</div>
</nav>
</div>
</div>
And this is part of the JS file:
var one = document.querySelector("#one");
var two = document.querySelector("#two");
var three= document.querySelector("#three");
const randomButton= document.querySelector("#randomButton");
function Randomizer() {
var array = [one, two, three];
var result = array[Math.floor(Math.random() * array.length)];
console.log(result);
var node = document.createElement("DIV");
node.innerHTML(result);
node.appendChild(result);
document.getElementById("#placeofresult").appendChild(node);
}
randomButton.addEventListener("click", Randomizer, false);
This if where I want that above div to be displayed:
<div>
<button class="btn btn-light" id="randomButton">
press!
</button>
<br>
<div id="placeofresult"> </div>
</div>
If I press the button, I want one of the divs from the Index file displayed in the div on the page where this JS belongs, but I don't know how to append a whole div by an id.
Thank you for your insights in advance!
appendChild will work fine if you need to insert div into another one.
Suppose, there is <div id="one">One</div> which you want to append inside <div id="placeofresult"></div>; you need to do the following
document.getElementById("placeofresult").appendChild(document.getElementById("one"));
or if you want to clone the div with id="one" and insert it, do the following:
const newOne = document.getElementById("one").cloneNode(true);
document.getElementById("placeofresult").appendChild(newOne);
Hope it helps. Revert for any doubts.
A solution for your problem could be to write the three divs you want to display entirely into js like this:
const divs = [
"
<div id="one">
...
</div>
",
"<div id="two">
...
</div>
",
"<div id="three">
...
</div>
"
]
Using your randomButton
randomButton.addEventListener("click", Randomizer, false);
You just have to set the innerHTML of your result div to the corresponding div of the divs array:
function Randomizer() {
var resultHTML = divs[Math.floor(Math.random() * array.length)];
document.getElementById("#placeofresult").innerHTML(resultHTML);
}
Another solution is to set the style of your divs to display none and display only the randomly chosen div after the button click:
Your html:
<div id="placeofresult">
<div id="one" style="display:none">
...
</div>
<div id="two" style="display:none">
...
</div>
<div id="three" style="display:none">
...
</div>
</div>
Your Randomizer:
function Randomizer() {
var array = [one, two, three];
// Set all divs to hidden
array.forEach(function(id){
document.getElementById(id).style.display = "none";
})
var result = array[Math.floor(Math.random() * array.length)];
document.getElementById(result).style.display = "block";
}
How do I loop thru array keys to output their values to HTML?
The layout I'm working with is a thumbnail grid, 3 columns by 2 rows. Each thumbnail has a caption below it. Selecting any of the thumbnails opens up a hidden container which is also a grid of 3 columns and 2 rows. Within that hidden container many of the images and captions are going to be identical so rather than have a whole bunch of duplicate HTML I figured I could just store each in an array and reference the values that each is associated with. I'm just stuck on how to create the loop at the moment.
var img=[
'image01.jpg','image02.jpg','image03.jpg','image04.jpg'
]
var details=[
'aaaaaa','bbbbbb','cccccc','dddddd'
];
$( "#yin" ).click(function() {
var img = [0,2];
var details = [0,1];
$(step).each(function() {
document.getElementById("img").innerHTML();
});
$(imgs).each(function() {
document.getElementById("img").innerHTML();
});
});
<div class="container">
<ul class="row-fluid">
<li class="span4" id="yin">
<div class="row-fluid">
<img src="yin.jpg" />
<h3>Yin</h3>
</div>
</li>
<li class="span4" id="yang">
<div class="row-fluid">
<img src="yang.jpg" />
<h3>Yang</h3>
</div>
</li>
</ul>
<div class="row-fluid">
<div class="span12">
<div class="show-details details">
<div class="detail-content">
<div id="img">
<!-- Loop (for yin would be image01, and image03) -->
</div>
<div id="details">
<!-- Loop (for yin would be 'aaaaaa','bbbbbb') -->
</div>
</div>
</div>
</div>
</div>
</div>
There's an issue with that code before you get into looping, the img and details variables are being re-declared inside your click function. What are they intended to be? From the comments in your code they seem to be specifying which indices of the array to use.
var images = ['image01.jpg','image02.jpg','image03.jpg','image04.jpg'];
var details = ['aaaaaa','bbbbbb','cccccc','dddddd'];
$( "#yin" ).click(function() {
var imgIndices = [0,2];
var detailIndices = [0,1];
$("#img").html("");
$("#details").html("");
$(imgIndices).each(function(i, o) {
$("#img").append("<img src=\"" + images[o] + "\"/>");
});
$(detailIndices).each(function(i, o) {
$("#details").append("<p>" + details[o] + "</p>");
});
});
<div class="container">
<ul class="row-fluid">
<li class="span4" id="yin">
<div class="row-fluid">
<img src="yin.jpg" />
<h3>Yin</h3>
</div>
</li>
<li class="span4" id="yang">
<div class="row-fluid">
<img src="yang.jpg" />
<h3>Yang</h3>
</div>
</li>
</ul>
<div class="row-fluid">
<div class="span12">
<div class="show-details details">
<div class="detail-content">
<div id="img">
<!-- Loop (for yin would be image01, and image03) -->
</div>
<div id="details">
<!-- Loop (for yin would be 'aaaaaa','bbbbbb') -->
</div>
</div>
</div>
</div>
</div>
</div>
I would take the click function out to a named function though and just pass in the arrays.