JQuery Multiple Hidden Values - javascript

I have the following HTML;
<ul class="list-group">
<li class="list-group-item">
www.andrewspiers.co.uk
<input type="hidden" name="url" value="www.andrewspiers.co.uk">
</li>
<li class="list-group-item">
wikipedia.org
<input type="hidden" name="url" value="wikipedia.org">
</li>
</ul>
The plan is to add a button to each row and then get the value from the hidden field when the button is clicked.
I have this;
alert( $('input[name="url"]').val() );
But that returns the value of the first row no matter which button is clicked.

This should work:
$('button').click(function(){
console.log($(this).closest('li').find('input[name="url"]').val())
})
You need to use $(this) within the click function to refer to that specific element and then traverse the DOM accordingly (multiple ways to skin a cat on this one) to get the hidden input.
jsFiddle example

Assuming your buttons are placed inside the same li, you need a more specific selector:
alert( $(this).siblings('input[name="url"]').val() );

You can add buttons like this :
$('.list-group-item').each(function(){
$(this).append('<input class="clicked" type="button" value="Click me"/>')
})
YOu can then get value of each hidden according to the button like this:
$('.clicked').on('click',function(){
var hiddenval =$(this).parent().find('input[name="url"]').val();
console.log(hiddenval);
})

Related

How to find the element and click by it's value?

I am doing a python selenium web driver project. Here is a button, I tried various ways, xpath, name,value,type,link text methods but it didn't work. I even tried to click by class name, but becuase the other button comes first, it clicks on that instead. Unlucky.
<li class="login_button">
<input type="button" value="Uygula" onclick="btnApply();">
<input type="button" onclick="window.location='/index.html'" value="Atla"> #I want to click this one.
</li>
I got this one also, but this is completely unrelated to this code above.
<li></li> #I wanna click this button.
As you can see, class, id, title all are the same. I can't click based on these. It seems there is only option that I can click through MyISP_PTM_35 thing but what is that? How to reach that?
There are three solutions that I think of immediately:
Find the element based on its value:
document.querySelectorAll("input").forEach(function(el){
if(el.value === "Atla"){
el.click();
}
});
<li class="login_button">
<input type="button" value="Uygula" onclick="btnApply();">
<input type="button" onclick="alert('Found It!')" value="Atla"> #I want to click this one.
</li>
Add a unique class to the element:
document.querySelector(".foo").click();
<li class="login_button">
<input type="button" value="Uygula" onclick="btnApply();">
<input type="button" class="foo" onclick="alert('Found It!')" value="Atla"> #I want to click this one.
</li>
Instead of finding the element, just so you can click it and perform some task, just perform the task:
function foo(){
alert("found it");
}
foo();
<li class="login_button">
<input type="button" value="Uygula" onclick="btnApply();">
<input type="button" onclick="foo()" value="Atla"> #I want to click this one.
</li>
Considering the HTML:
<li class="login_button">
<input type="button" value="Uygula" onclick="btnApply();">
<input type="button" onclick="window.location='/index.html'" value="Atla"> #I want to click this one.
</li>
To click on the element with value as Atla you can use either of the following locator strategies:
Using css:
let loginButton = driver.findElement(By.css("li.login_button input[value='Atla'][onclick*='index']"));
await loginButton.click();
Using xpath:
let loginButton = driver.findElement(By.name("//li[#class='login_button']//input[#value='Atla' and contains(#onclick, 'index')]"));
await loginButton.click();

jquery mobile listview count items after filter

I need some help. I am trying to display the number of visible listview items after filter has been applied, either by a button click or by applying a text filter. The button clicks simply put text into the text filter and so it's all the same trigger point hopefully.
Html is pretty much like this...
<div>
<form class="ui-filterable">
<input id="myFilter" data-type="search" placeholder="Text Filter...">
</form>
<div data-role="fieldcontain">
<input type="button" data-inline="true" value="More Info Provided" id="more-info-provided-filter" />
<input type="button" data-inline="true" value="In Progress" id="in-progress-filter" />
</div>
<p id="listInfo"></p>
<ol data-role="listview" id="myList" data-filter="true" data-input="#myFilter"></ol>
</div>
And my javascript for each button click is just like this...
$(document).on('click', '#in-progress-filter', function(){
$('input[data-type="search"]').val('in progress');
$('input[data-type="search"]').trigger("keyup");
var volListItemsDisplayed;
volListItemsDisplayed = $("#myList li:visible").length;
document.getElementById("listInfo").innerHTML = "Number of items (filter on): " + volListItemsDisplayed;
});
The javascript fires before the filter is applied. Is there a way that I can attach my function to the filter, like an onchange type of event? You can assume the listview is populated with records containing either of the text strings being applied by the buttons.
Thanks
With JQM you can do it following way:
$(document).on("pagecreate", "#search-page-id", function(e) {
$("#my-list" ).on("filterablefilter", function(e, data) {
var result = $(this).children("li").not(".ui-screen-hidden").length;
console.log("FILTERED ITEMS: ",result);
});
});
If inside your listview you have also list dividers, you may narrow down the filter by excluding them:
var result = $(this).children("li").not("[data-role=list-divider]").not(".ui-screen-hidden").length;

jQuery product filter using checkboxes and :contains() show/hide

I'm attempting to put together a simple jQuery product filter for a store that lists all products of a category on one page. This can't be achieved through AJAX because of the way the store is set up.
Simply put, all products of the category are on one page. They have varying brands product names and team names. The markup looks something like this (the form at the end is how I'm planning on doing the filter).
<div id="CategoryContent">
<ul>
<li class="product">Brand1 PRODUCT1 TeamA</li>
<li class="product">Brand1 PRODUCT2 TeamB</li>
<li class="product">Brand2 PRODUCT3 TeamB</li>
<li class="product">Brand2 PRODUCT4 TeamC</li>
<li class="product">Brand3 PRODUCT5 TeamA</li>
<li class="product">Brand3 PRODUCT6 TeamD</li>
<li class="product">Brand4 PRODUCT7 TeamD</li>
<li class="product">Brand1 PRODUCT8 TeamA</li>
<li class="product">Brand1 PRODUCT9 TeamA</li>
<li class="product">Brand1 PRODUCT10 TeamB</li>
<li class="product">Brand4 PRODUCT11 TeamD</li>
<li class="product">Brand2 PRODUCT12 TeamA</li>
</ul>
<div style="clear:both;"></div>
<div class="filter">
<form id= "brandfilter" action="">
<h2>Brands:</h2>
<input type="checkbox" name="brand" value="Brand1"/>Brand1 </br>
<input type="checkbox" name="brand" value="Brand2"/>Brand2 </br>
<input type="checkbox" name="brand" value="Brand3"/>Brand3 </br>
<input type="checkbox" name="brand" value="Brand1"/>Brand4 </br>
</form>
<form id="teamfilter" action="">
<input type="checkbox" name="team" value="TeamA"/>TeamA </br>
<input type="checkbox" name="team" value="TeamB"/>TeamB </br>
<input type="checkbox" name="team" value="TeamC"/>TeamC </br>
<input type="checkbox" name="team" value="TeamD"/>TeamD </br>
</form>
I have found this filter works as I want. In console replacing hide with show and Brand1 with Brand2, TeamA, etc works just fine.
$("#CategoryContent li").not(
$("#CategoryContent li:contains(Brand1)")
).hide();
The next step is getting a double filter which works as well:
$("#CategoryContent li").not(
$("#CategoryContent li:contains(Brand1):contains(TeamA)")
).hide();
My problem with getting this working is two fold. 1 is replacing the Brand1 / Team A with variables (hence the formids).
The second is trying to run the script when a checkbox is clicked. It should work if either one is clicked and if both are clicked (meaning that with the script above it would need to reset by showing all and then hiding).
Currently to initiate it I'm running this script but I'm running into problems so I've gone back to just 1 filter.
$("input:checkbox[name='brand']").click(function() {
var brandfilter = $(this).val();
alert (brandfilter);
$("#CategoryContent li:contains(' + brandfilter + ')").parent().hide();
});
The alert that pops up is what I want (i.e. Brand1) but the hide function afterwards doesn't work and when I alert (brandfilter) again in console again I get [object HTMLFormElement]. So I think the variable isn't storing correctly or something?
Here is the simple working basic script http://jsfiddle.net/7gYJc/
Assuming you want to show items which match any currently ticked box, you can use this:
$('input:checkbox').change(showHideProducts);
function showHideProducts()
{
var checked = $('input:checked');
var products = $('.product');
// If all the boxes are unchecked, show all the products.
if (checked.length == 0)
{
products.show();
}
else
{
products.hide();
checked.each
(
function()
{
$('.product:contains("' + $(this).val() + '")').show();
}
);
}
}​
EDIT: Since you want all the boxes to display when nothing is checked, just add an if (length = 0) check and show everything in there (see above).
I can't tell where the problem is but you can try using filter() instead of the :contains selector. With filter() you can create your own custom filtering rules as it takes a function as parameter.
var myProducts = function (brand, team) {
brand = brand || '';
team = team || '';
return $('.product').filter(function () {
var re = new RegExp(brand + '.+' + team, 'i');
return re.test($(this).text());
});
};
myProducts('Brand1', 'TeamA').hide();
myProducts('Brand2').hide();
Example: http://jsfiddle.net/elclanrs/hYZcW/
I came up with the following approach:
Start with all the checkboxes checked, because you want to show all the products. If the user unticks a checkbox, then it should hide products matching that brand/team.
Here is the code I had:
var $filters = $("input:checkbox[name='brand'],input:checkbox[name=team]").prop('checked', true); // start all checked
var $categoryContent = $('#CategoryContent li'); // cache this selector
$filters.click(function() {
// if any of the checkboxes for brand or team are checked, you want to show LIs containing their value, and you want to hide all the rest.
$categoryContent.hide();
$filters.filter(':checked').each(function(i, el) {
$categoryContent.filter(':contains(' + el.value + ')').show();
});
});​
jsFiddle link.
I had the same kind of problem this week with multiple selects. The selectors worked fine, but hide did not work. I was able to solve it using
.css('visibility', 'hidden'); // instead of .hide() and
.css('visibility', ''); // instead of .show()
I do not understand it, but it worked.

jQuery + Appending a clone multiple times, at different times?

I have this form which has a section where a user can specify an indefinite number of value pairs, specifically, a language and a level of proficiency.
I have the DOM structured like this:
<ul id="language-list">
<li class="user-language-item">
<select name="language[]" class="user-language-select">...</select>
Level: <select name="proficiency[]">...</select>
<input type="button" value="Remove" class="remove-language" />
</li>
<li class="user-language-item">
<select name="language[]" class="user-language-select">...</select>
Level: <select name="proficiency[]">...</select>
<input type="button" value="Remove" class="remove-language" />
</li>
<li class="user-language-item">
<select name="language[]" class="user-language-select">...</select>
Level: <select name="proficiency[]">...</select>
<input type="button" value="Remove" class="remove-language" />
</li>
</ul>
<input type="button" value="Add another language..." id="add-a-language" />
If the user clicks on the Add another language... button, a new list item containing the same form elements should be inserted to the list.
And here is my code:
$(function(){
//Save a clone of one list item during initialization.
var liItem = $('.user-language-item').last().clone();
$('#add-a-language').click(function(){
//Append the clone to the list item. But this only works once!
$('#language-list').append(liItem);
});
//Note that there might be an instance where there are no list items present, which is why I opted to clone the a list item during initialization.
$('.remove-language').live('click', function(){
$(this).parents('li.user-language-item').fadeOut(500, function(){
$(this).remove();
});
});
});
But the clone seems to be only usable once. Upon clicking the Add a language... button the second time, no list item is appended. (Interestingly, when I output the variable on the console, it still contains the clone!)
One way around this would be saving the HTML mark-up as a string, but I am avoiding this approach as the elements are dynamically loaded via PHP, and I'd rather just change one part of my code whenever I need to modify the mark-up.
How can I possibly make this work?
You will have to clone it every time when you want to add
$('#add-a-language').click(function(){
var liItem = $('.user-language-item').last().clone();
//Append the clone to the list item. But this only works once!
$('#language-list').append(liItem);
});
Demo
As per comment:
Keep one li like this:
<li class="user-language-item hidden" id="placeHolderLi">
<select name="language[]" class="user-language-select">...</select>
Level: <select name="proficiency[]">...</select>
<input type="button" value="Remove" class="remove-language" />
</li>
Where .hidden just marks it to display:none;
.hidden{
display:none;
}
Then while cloning you always clone this li and make it visible so that even if user has deleted all the li, new elements can still be added.
$('#add-a-language').click(function(){
var liItem = $('.user-language-item:first').clone(true).show();
//Append the clone to the list item. But this only works once!
$('#language-list').append(liItem);
});
Demo

How to loop over nested input forms with jquery

I have the following html form, which is generated dynamically:
<ul class="precursorList">
<li>
Precursor Name: <input name="precursorName" type="text">
<ul class="portList">
<li>Portname of precursor: <input name="precursorPort" type="text">
Portname of this: <input name="thisPort" type="text">
</li>
</ul>
</li>
<li>
<li>
Precursor Name: <input name="precursorName" type="text">
<ul class="portList">
<li>Portname of precursor: <input name="precursorPort" type="text">
Portname of this: <input name="thisPort" type="text">
</li>
</ul>
</li>
<li>
</ul>
I want to get the values using jquery, therefore I have defined this loop:
ports = [];
$(".precursorList :input").each(function() {
if(this.name == "precursorName") {
var precursorName_ = this.value
$(".portList :input ").each(function() {
if(this.name == "precursorPort") {
precursorPort_ = this.value;
} else if(this.name == "thisPort") {
ports.push({
filterName : precursorName_,
portNameOfFilter : precursorPort_,
portNameOfThis : this.value
});
}
});
}
});
Unfortunately this function does not work like I want it to work. The following loop $(".portList :input ").each( will always only loop over all elements in portList in the html document. How can I achieve that this loop will only loop over the corresponding portList, for each precursor?
UPDATE: The structure of the html element will stay the same only, the number of inputs will change. But there will only be a portList if a PrecursorElement exist.
id must be a unique field, instead use class to select multiple elements. Also use .live() for dynamically added elements.
EDIT:
If you are using Jquery > 1.7 use .on() instead of .live().
I tried following and it seems that its working
$(".precursorPort").each(function() {
temp = this.name;
$(this).parents(".portList").each(function() {
$(this).parents(".precursorList").each(function() {
alert(temp);
// use temp var and save it in ports
});
});
});
Check this fiddle : http://jsfiddle.net/Ajinkya_Parakh/DR233/
It may not be the best/most efficient but it is one of the working alternative.
An id must be unique in a document. If you want to create a group of similar things, then use a class instead.
I'd do something like this:
<ul id="precursorList">
<li>
Precursor Name1: <input class="precursor" name="precursorName1" id="precursorName1" type="text">
<ul id="portList1">
<li>Portname of precursor1: <input class="precursorPort" name="precursorPort1" id="precursorPort1" type="text">
Portname of this1: <input class="thisPort" name="thisPort1" id="thisPort1" type="text">
</li>
</ul>
</li>
<li>
Precursor Name2: <input class="precursor" name="precursorName2" id="precursorName2" type="text">
<ul id="portList2">
<li>Portname of precursor2 <input class="precursorPort" name="precursorPort2" id="precursorPort2" type="text">
Portname of this2: <input class="thisPort" name="thisPort2" id="thisPort2" type="text">
</li>
</ul>
</li>
</ul>
and then:
ports = [];
$("#precursorList > li").each(function()
{
precursor = $(this).find(".precursor")[0];
precursorPort = $(this).find(".precursorPort")[0];
thisPort = $(this).find(".thisPort")[0];
ports.push({filterName: precursor.value, portNameOfFilter: precursorPort.value, portNameOfThis: thisPort.value});
});
Step back a minute, I think you're overthinking this a bit.
Wrap your dynamic form in <form> tags. Then do a $('form').serialize() No need for crazy loops. Serialize is essentially a built-in, one line version of what you're already trying to do. Of course, serialize works on names so you'll have to have distinct ones (even if it's just name1, name2,etc) ID's must be unique too, so either fix that or drop them.
Simplicity always trumps crazy technical genius.
Fiddle for proof

Categories