Compare elements by attribute and show the correct one - javascript

I have this list with divs and a dropdown menu. The list with divs and the dropdown menu divs have the same data attribute (data-num). When a div in the dropdown menu is clicked I want to show the div with the same data attribute and hide the others. I tried something like this but it's only giving me the first div from the list:
$('#chooseAnnexDropdown ul li').each(function(){
var that = $(this);
var sibs = $(this).siblings();
var thisAttr = $(this).attr('data-num');
var thisParent = $(this).parent().parent().parent().parent();
var theProducts = thisParent.find('.theProduct');
var theProductsAttr = $(theProducts).attr('data-num');
console.log(theProductsAttr);
that.click(function(){
if ( thisAttr === theProductsAttr ) {
// show the product div with the correct attribute and hide the others
}
});
});
So how do i loop through each element in my dropdown and then compare it to my other list and show the correct div?
Here is some of the HTML code:
<div id="configurator">
<!-- dropdown menu -->
<div id="chooseAnnexDropdown" class="confDropdown">
<ul>
<li class="block_2" data-num="block_2">Atelier</li>
<li class="block_3" data-num="block_3">Bryggerhus</li>
<li class="block_4" data-num="block_4">Smørebod</li>
<li class="block_5" data-num="block_5">Bakstehus</li>
<li class="block_6" data-num="block_6">Sportsrom</li>
<li class="block_7" data-num="block_7">Boenhet</li>
<li class="block_8" data-num="block_8">Ingen</li>
</ul>
</div>
<!-- end dropdown menu -->
{% for i in 1..39 %}
{% for block in entry['hyttekonf' ~i] %}
<div class="theProduct" data-num="block_{{ i }}" id="block_{{ i }}">
<div class="conf-image absolutecenter">
{% set image = block.bilde.first() %}
<img src="{{ image.getUrl('plantegningKonfigurator') }}" alt="{{ image.title }}" />
</div>
</div>
{% endfor %}
{% endfor %}
</div>

I guess you are looking for this.
$('#chooseAnnexDropdown ul li').click(function(){
var thisParent = $(this).parent().parent().parent().parent();
thisParent.find('.theProduct[data-num=' + $(this).attr('data-num') + ']').show().siblings().hide();
});

I'm guessing at your HTML structure, but based on what it looks like you are doing, you can add your click handler to all the "li" elements and in that handler, just find the matching item to show and then hide it's siblings.
$('#chooseAnnexDropdown ul li').click(function(){
var dataNum = $(this).attr('data-num');
//this could be done in a better way
var thisParent = $(this).parent().parent().parent().parent();
thisParent.find('.theProduct[data-num=' + dataNum + ']').show().siblings().hide();
});
Seeing your actual HTML would help though.

You can modify your JS code as follows:
Here we are hiding all the div on document ready and then on click of li we are grabbing its data-num and then finding the associated div to show it.
$(document).ready(function() {
$(".theProduct").hide(); //hide all div first
$('#chooseAnnexDropdown ul li').click(function() {
var thisAttr = $(this).attr('data-num');
$(".theProduct").hide(); //hide all div first
$("div[data-num='" + thisAttr + "']").show(); //show the matching div
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<!-- dropdown menu -->
<div id="chooseAnnexDropdown" class="confDropdown">
<ul>
<li class="block_2" data-num="block_2">Atelier</li>
<li class="block_3" data-num="block_3">Bryggerhus</li>
<li class="block_4" data-num="block_4">Smørebod</li>
<li class="block_5" data-num="block_5">Bakstehus</li>
<li class="block_6" data-num="block_6">Sportsrom</li>
<li class="block_7" data-num="block_7">Boenhet</li>
<li class="block_8" data-num="block_8">Ingen</li>
</ul>
</div>
<!-- end dropdown menu -->
<div class="theProduct" data-num="block_2" id="block_2">Atediver</div>
<div class="theProduct" data-num="block_3" id="block_3 ">Bryggerhus</div>
<div class="theProduct " data-num="block_4" id="block_4">Smørebod</div>
<div class="theProduct " data-num="block_5" id="block_5">Bakstehus</div>
<div class="theProduct " data-num="block_6" id="block_6">Sportsrom</div>
<div class="theProduct " data-num="block_7" id="block_7">Boenhet</div>
<div class="theProduct " data-num="block_8" id="block_8">Ingen</div>

Related

jQuery to close menu when form submitted / prevent function on error + update list with htmx

So what I have is a simple form with couple of fields that is located inside a menu, that slides in when I click button 'btn-openmenu'. I am trying to use htmx to dynamically update the page to show results instantly and also Javascript to control the menu where the form is located.
What I am trying to accomplish is that when the submit button on the form is pushed, it will submit the form and close the menu.
What happens now is that the menu closes okay when the form is submitted. What also can happen is that if the form is not valid and a error pops up, but the menu still closes and the form is never submitted.
Here is the html where form is located form (/items/new-item/):
{% load crispy_forms_tags %}
<form id="createnewitem"
hx-post="/items/new-item/">
{% csrf_token %}
{{ newcoreprocess|crispy }}
<div style="margin-top: 10px;">
<button type="submit" class="btn submit-new">Create item</button>
<a class="btn" id="clear">Clear</button>
</div>
</form>
<script>
$(document).ready(() => {
$('#clear').on('click', function () {
var form = $("#createnewitem");
form[0].reset();
})
})
</script>
<script>
$(document).ready(() => {
$('.submit-new').click(function () {
var pagecontent = $("#content");
var menu = $(".menu");
var buttonSpan = $("#btn_openmenu").find('span');
pagecontent.css('marginLeft', '0');
menu.css('width', '0');
buttonSpan.text('Close');
})
})
</script>
Here is the html where the menu is opened and updated list would be rendered (/items/):
<div class="items-content" id="itemcontent">
<div class="container-fluid">
<div class="row" id="items-list">
{% include 'items/items-list.html' %}
</div>
</div>
<button class="btn" id="btn_openmenu"
hx-get="/items/new-item/"
hx-target="#createitemmenu"
hx-swap="innerHTML">
<i class="fas fa-plus-circle" id="add-item-icon"></i><span class="spanicon" id="add-item-span">Create item</span>
</button>
<div class="menu">
<div class="container-fluid" id="createitemmenu">
</div>
</div>
</div>
<script>
$(document).ready(() => {
$('#btn_openmenu').on('click', function () {
var thisElement = $(this);
var buttonSpan = thisElement.find('span');
var pagecontent = $("#itemcontent");
var menu = $(".menu");
if(buttonSpan.text() === "Close"){
buttonSpan.text('Create item');
menu.css('width', '0');
pagecontent.css('marginLeft', '0');
}
else {
if(buttonSpan.text() === "Create item"){
buttonSpan.text('Close');
pagecontent.css('marginLeft', '20%');
menu.css('width', '20%');
}
}
})
})
</script>
And here is the list (/items/item-list/)
{% if items %}
<nav class="nav processnav flex-column" style="padding-top: 10px;">
{% for item in items %}
<a class="nav-link" href="#">{{ item.order }} {{ item.name }}</a>
{% endfor %}
</nav>
{% else %}
<div class="container-fluid mt-3">
<span>No created items</span>
</div>
{% endif %}
What is working:
menu opens correctly
htmx renders the form in the menu
form can be submitted and if valid, the menu will close
What is not working:
if errors on submit, it still closes the menu
I have tried to edit the function submit-new.click, but whatever I change in that, it stops working at all and this is only function I got to work with valid submit
htmx doesn't render the updated list where new item is created
I have tried to edit the hx-post in the form, but whatever I edit the new item submit stops working and it renders some other content to the place, where the form is located.
I think there are just little things I am missing, but I cannot seem to get it function the way I want. Any help for the issue?

Validate if 2 elements have same attribute value

In my e-commerce environment, I need a jQuery validation between 2 product attributes. Simplified it needs to check if the cart has a product which is present on the same page:
<! –– Cart ––>
<ul class="woocommerce-mini-cart cart_list product_list_widget ">
<li class="woocommerce-mini-cart-item mini_cart_item">
<a href="/example-product/" class="remove remove_from_cart_button" data-product_id="6735" data-cart_item_key="..." ></a>
</li>
</ul>
<! –– Product ––>
<article class="post-6735 product" data-id="6735">
<div class="product_wrapper">
<a href="?add-to-cart=6735" data-quantity="1" class="button add_to_cart_button" data-product_id="6735"</a>
</div>
</article>
I would like to be able to check if the attribute and its value from data-product_id within the cart is the exact same as in article a.button element. My approach:
jQuery('.woocommerce-mini-cart .remove_from_cart_button').attr('data-product_id').each( function() {
if( jQuery('article a.button')/*check if it is the same*/){
// do something here
}
});
As you can see the ID number 6735 is in more attributes. So perhaps a different way is also possible?
To get current_ProductId, You just need to get from $('article').data('id')
To loop through all mini cart items, You just need mini_cart_item
As you can see, we can get data attribute value by using data
var current_ProductId = $('article').data('id');
$('.mini_cart_item').each(function() {
var productId_MiniCartItem = $(this).find('a').data('product_id');
if(productId_MiniCartItem == current_ProductId){
// do something here
console.log("ProductId: " + productId_MiniCartItem + " has been ordered");
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<! –– Cart ––>
<ul class="woocommerce-mini-cart cart_list product_list_widget ">
<li class="woocommerce-mini-cart-item mini_cart_item">
<a href="/example-product/" class="remove remove_from_cart_button" data-product_id="6735" data-cart_item_key="..." >6735</a>
</li>
<li class="woocommerce-mini-cart-item mini_cart_item">
<a href="/example-product/" class="remove remove_from_cart_button" data-product_id="6736" data-cart_item_key="..." >6736</a>
</li>
</ul>
<! –– Product ––>
<article class="post-6735 product" data-id="6735">
<div class="product_wrapper">
<a href="?add-to-cart=6735" data-quantity="1" class="button add_to_cart_button" data-product_id="6735"</a>
</div>
</article>
If you only need help to clarify your solution it would be
$('.woocommerce-mini-cart .remove_from_cart_button').each( function() {
if( $('article a.button').data('product_id') == $(this).data('product_id'){
// do something here
}
});
each iterate through collection of jquery elements.
This
jQuery('.woocommerce-mini-cart .remove_from_cart_button').attr('data-product_id')
is the single value, it would take the first element that finds and then executes attr on it.
UPDATE
To update all products button on site based on all products that are inside the card
var product_id = "";
var article = ".post-"; // class of article
$('.woocommerce-mini-cart .remove_from_cart_button').each( function() {
product_id = $(this).data('product_id')
article = article + product_id; // we add strings here, example .post-6225
$(article + " .product_wrapper a").attr('disabled', 'disabled');
});

Add class to elements with same id on click, remember class on page refresh

I'm trying to build a page that contains multiple inner pages - a front page that displays by default, and child pages which display when relevant links on the front page are clicked.
What I am trying to achieve is that when a page-link element is clicked, the class active-page is added to the inner page with the same id, and the intro section has a class off-canvas added, & the active page is set in localStorage - so that if for any reason the page is refreshed, the last page that was being viewed is displayed.
Alternatively, when a lnk-rtn-home element is clicked, the current inner-page should lose the active page class while front-page loses its off-canvas class. Likewise, this should update the localStorage.
The HTML structure is as follows:
<body>
<div class="container">
<section id="intro" class="front-page row">
{{ content }}
<a data-id='about-me' class='page-link'>About Me</a>
{{ more content }}
<a data-id='contact' class='page-link'>Contact</a>
</section>
<section id="about-me" class="inner-page row">
{{ content }}
<a class='lnk-rtn-home'>Return Home</a>
</section>
<section id="contact" class="inner-page row">
{{ content }}
<a class='lnk-rtn-home'>Return Home</a>
</section>
</div>
</body>
The current JS stands at
$(document).ready(function(){
var activePageSet = localStorage.getItem('current-page');
// Check if an active page has been set
if (activePageSet) {
$('#' + activePageSet).addClass('active-page');
$('#intro').addClass('off-canvas');
}
// Links to inner pages
$('.page-link').click(function() {
var currentPage = $(this).data("id");
$('#' + currentPage).addClass("active-page");
$('#intro').addClass('off-canvas');
localStorage.setItem('current-page', JSON.stringify(currentPage));
});
// Link to return home
$('.lnk-rtn-home').click(function() {
if ($('.inner-page').hasClass('active-page')) {
$(this).removeClass('active-page');
localStorage.removeItem('current-page');
}
$('#intro').removeClass('off-canvas');
});
});
No amount of playing around with this has got it working, and at this stage I'm lost as to how to achieve it.
This problem can be solved with using only 1 class. You have made your code more complex by using 2 classes. I replaced .active-page and .off-canvas with the class .hidden. This gives a simpler code to follow.
var activePageSet = null; //localStorage.getItem('current-page');
//not able to do localStorage in snippet
// Check if an active page has been set
if (activePageSet) {
$('#' + activePageSet).removeClass('hidden');
$('#intro').addClass('hidden');
}
// Links to inner pages
$('.page-link').click(function() {
var activePageId = $(this).data("id");
$('#' + activePageId).removeClass("hidden");
$('#intro').addClass('hidden');
//localStorage.setItem('current-page', JSON.stringify(activePageId));
});
// Link to return home
$('.lnk-rtn-home').click(function() {
var activePage = $(this).parent();
activePage.addClass('hidden');
$('#intro').removeClass('hidden');
//localStorage.removeItem('current-page');
});
.hidden {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<section id="intro" class="front-page row ">
{{ intro content }}
<a data-id='about-me' class='page-link'>About Me</a>
{{ more content }}
<a data-id='contact' class='page-link'>Contact</a>
</section>
<section id="about-me" class="inner-page row hidden">
{{ about content }}
<a class='lnk-rtn-home'>Return Home</a>
</section>
<section id="contact" class="inner-page row hidden">
{{ contact content }}
<a class='lnk-rtn-home'>Return Home</a>
</section>
</div>
you just need to select right element for hasClass condition.
You can use a parent, like this:
$(document).ready(function(){
// Links to inner pages
$('.page-link').click(function() {
var currentPage = $(this).data("id");
$('#' + currentPage).addClass("active-page");
$('#intro').addClass('off-canvas');
//localStorage.setItem('current-page', JSON.stringify(currentPage));
});
// Link to return home
$('.lnk-rtn-home').click(function() {
var jqSection = $(this).parent();
if (jqSection.hasClass('active-page')) {
jqSection.removeClass('active-page');
localStorage.removeItem('current-page');
}
$('#intro').removeClass('off-canvas');
});
});
Here is an example: https://plnkr.co/edit/xfgHpWdDpnDTyjLYYrGd?p=preview

jQuery selector problems

I have some tabs' info rendered with handlebars and here is my HTML:
<ul class="nav nav-tabs" id="tabsId">
<script id="tabs-template" type="text/x-handlebars-template">
{{#each Tabs}}
<li data-tab-content={{Id}}>{{Name}}</li>
{{/each}}
</script>
</ul>
<div id="tabsContentId">
<script id="tabs-content-template" type="text/x-handlebars-template">
{{#each Tabs}}
<div class="tab-content" data-tab-content="{{Id}}">{{Content}}</div>
{{/each}}
</script>
</div>
And now I'm writing a function that will fill my future form when I double click on any tab. I've only managed how to get id and I don't understand how to get name and content values. I've tried to use jQuery .text() function, but I've failed. Here is my function:
$(function() {
$("#tabsId").on("dblclick", "li", function(evt) {
evt.preventDefault();
var id = $(this).data("tabContent");
//var name = ?
//var content = ?
$('#inputIndex').val(id);
//$('#inputTitle').val(name);
//$('#textareaContent').val(content);
});
});
var id = $(this).data("tab-content");
var name = $(this).text();
// Get the content from the nth element in the other list (using the index of the LI clicked)
var content = $('#tabs-content-template .tab-content').eq($(this).index()).text();
Note: this only works as the same collection is used for both the LIs and the tab DIVs. Otherwise you will need to find it via the data-tab-content attribute.
Use $(this).text() then you can get the name in the dbclicked li.
Use $('#tabsContentId div[data-tab-content="' + id + '"]'); so you can get the target div which has an attribute data-tab-content and value is the id you previously retrieved.
$(function() {
$("#tabsId").on("dblclick", "li", function(evt) {
evt.preventDefault();
var id = $(this).data("tabContent");
var name = $(this).text();
alert("Name is :" + name);
var targetDiv = $('div.tab-content[data-tab-content="' + id + '"]');
var content = targetDiv.text();
alert("Content is :" +content);
$('#inputIndex').val(id);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="nav nav-tabs" id="tabsId">
<li data-tab-content="t1">I'm Name</li>
</ul>
<div id="tabsContentId">
<div class="tab-content" data-tab-content="t1">Here's content</div>
</div>
Not exactly sure what you're after, but this would get the inner HTML of the first <a> element with href="#" inside the clicked element:
var name = $(this).find('a[href="#"]').first().html();

Isolate specific HTML elements with jQuery

OK, what I need may sounds rather complex, but here it is...
Let's say we have the HTML code below (it's still just an example, but it's still quite accurate) :
<div data-role="content" comp-id="jqm-content-6207" id="jqm-content-6207" class="" data-theme="" >
<!-- New Navigation Bar #1 -->
<div data-role="navbar" data-position="fixed" comp-id="jqm-navbar-4603" id="jqm-navbar-4603" class="" data-iconpos="top" >
<ul>
<!-- New Navigation Bar Item #1 -->
<li>
<a href="#" comp-id="jqm-navbar-item-6671" id="jqm-navbar-item-6671" class="" data-icon="home" data-theme="" >
One
</a>
</li>
<!-- / New Navigation Bar Item #1 -->
<!-- New Navigation Bar Item #2 -->
<li>
<a href="#" comp-id="jqm-navbar-item-4404" id="jqm-navbar-item-4404" class="" data-icon="gear" data-theme="" >
Two
</a>
</li>
<!-- / New Navigation Bar Item #2 -->
</ul>
</div>
<!-- / New Navigation Bar #1 -->
<!-- New Navigation Bar #2 -->
<div data-role="navbar" data-position="fixed" comp-id="jqm-navbar-4658" id="jqm-navbar-4658" class="" data-iconpos="top" >
<ul>
<!-- New Navigation Bar Item #2.1 -->
<li>
<a href="#" comp-id="jqm-navbar-item-5321" id="jqm-navbar-item-5321" class="" data-icon="home" data-theme="" >
One
</a>
</li>
<!-- / New Navigation Bar Item #2.1 -->
<!-- New Navigation Bar Item #2.2 -->
<li>
<a href="#" comp-id="jqm-navbar-item-2843" id="jqm-navbar-item-2843" class="" data-icon="gear" data-theme="" >
Two
</a>
</li>
<!-- / New Navigation Bar Item #2.2 -->
</ul>
</div>
</div>
First-off, the core idea is : when the user clicks an item with the comp-id attribute set, then add class msp-selected just to this specific element (and remove it from all other elements).
This is how I'm handling this specific part :
function removeAll()
{
$("*").each(function() {
if ($(this)!==undefined) {
$(this).removeClass("msp-selected");
}
});
}
$(document).ready( function() {
$('[comp-id]').bind('click', function(event) {
removeAll();
$(event.target).addClass('msp-selected');
});
});
So, as you may already have guessed it's like a way of "selecting" item (by clicking on them) from the HTML document.
Now, here's the catch :
How could I make it so that the "selection" is progressive?
What I mean...
When the user first clicks on the Navigation Bar :
Check if the first div with comp-id is selected (has the class msp-selected). If not, select it.
If the first div is already selected, then go one level deeper looking for comp-id, and select that one.
So, any ideas?
How would you do it?
P.S. When one clicks on the <a> of a navigation item, what specific item receives the event?
Is it the <div data-role=\"navbar\"> or the navigation bar item? No matter what, from all these items, I want to select the outermost - not being currently selected. Next time, when the user clicks again and e.g. the navigation bar is selected, then unselect it and select it's child (go deeper).
EDIT :
When trying :
$(document).ready( function() {
$('[comp-id]:not(.msp-selected)').on('click', function(e) {
removeAll();
$(this).addClass('msp-selected');
});
});
What I'm getting when clicking on navbar-item is :
Selected Div : jqm-navbar-item-8421
Selected Div : jqm-navbar-8598
Selected Div : jqm-content-2860
Selected Div : jqm-page-3363
So, basically it just "selects" the outermost container. Which is wrong... Next time the user clicks, the content should selected - then the navbar and then the navbar-item....
You may write a function like that (i am not sure if the syntax is correct)
function onclick(sender)
{
if(type of sender == null )
{
return;
}
if(sender.className=="selected")
{
onclick(sender.childElement[0]);
// OR If you need all children to be selected,
// for( var i =0; i<sender.childElement.count; i++)
// onclick(sender.childElement[i]);
}
else
{
sender.className="selected";
}
}

Categories

Resources