jQuery selector for varying HTML structure - javascript

I'm working with a page which displays a product's price. Normally it looks like this:
<span id="priceText">
$26.94
</span>
When the item is on sale, it looks like this:
<span id="priceText">
<strike>$26.94</strike>
<span class="salePrice">$25.00</span>
</span>
I have a generic function which extracts the price from any page like so:
var getPrice = function(price_id) {
return jQuery(price_id).text();
};
Where price_id is the id of the element which contains the price.
As is plainly obvious, this will not work with the above structure since the "sale" version will return both $26.94 and $25.00 if I set price_id to priceText
I do not have control over the html on the product's page, so I can't change the structure. I need to use the getPrice function on other pages which do not have this HTML structure, so I also want to avoid changing it.
What I am looking for is some sort of jQuery selector which will return $25.00 if the item is on sale, or $26.94 if it isn't. Something like "return all text inside of priceText NOT in a strike tag"
I currently have a custom snippet which does the following:
jQuery('#priceText .salePrice').length ? jQuery('#priceText .salePrice').text() : jQuery('#priceText strike').text()
However I want to avoid custom lines of code like this. I think this may not be possible using only jQuery selectors but I'm hoping someone proves me wrong!

You can use a multiple selector.
jQuery('#priceText .salePrice, #priceText:not(:has(.salePrice))').text()
DEMO

Maybe you could reduce your condition by this:
($('#priceText .salePrice') || $('#priceText strike')).text()

Related

Changing inner HTML of a button with dynamic id

On a project I'm working on, a HTML file is defining a Javascript template used on selection buttons. All buttons have a "Change..." label that I want to localize (set dynamically). In other cases I'm searching for the element ID and setting the InnerHTML accordingly. But in this case, the ID of the buttons are defined dynamically. Is it possible to have a text element inside the button element, search for this element, and set its InnerHTML value?
<script id="optionSelectionTemplate" type="text/x-handlebars-template">
<div class="sub-section option-selection">
{{#if name}}<h4>{{name}}</h4>{{/if}}
<div class="current"></div><button class="button" id="{{id}}" data-action-id="{{id}}">Change...</button>
</div>
</script>
I've been searching this for a while now. But given that my forte is not web development, I'm not really sure what to search for...
You may be able to get the button element(s) by its class instead; for example:
var x = document.getElementsByClassName("button");
As you suggested, you can improve your selection's precision by first getting the 'optionSelectionTemplate' element(s) like so:
var x = document.getElementById("optionSelectionTemplate").getElementsByClassName("button");
Or if you prefer:
var x = document.getElementById("optionSelectionTemplate").getElementsByTagName("button");
Here are some links for more on these method:
https://www.w3schools.com/jsref/met_document_getelementsbyclassname.asp
https://www.w3schools.com/jsref/met_document_getelementsbytagname.asp
Depending on how dynamic your localization should become, you could also specify the text inside a (locale-dependent) CSS as in https://jsfiddle.net/1gws5kat/ :
[HTML]
<button class="button btn_change" id="{{id}}" data-action-id="{{id}}"></button>
[CSS]
.btn_change:before { content: "Change..."; }
In particular when dealing with a large number of identically-named elements (i.e. many "Change" buttons), this might be pretty handy.
You find those btns by this command:
var btnlist= $(':button')
This Camano get you all button in your html file, then loop ton in and apply your changing.
Before call this command, jquery must be install.

Extract text from class using javascript

I have a couple of dashboard pages rendered and view elements coded for one page that looks like:
<td class="secondaryTabSelected" title="Pace">
<span tabindex="0">Pace</span>
</td>
I want to extract the name called "Pace" from above using Javascript, after the user has clicked on a specific tab title called "Pace". How can I achieve this?
I have tried:
var a = document.getElementsByClassName('secondaryTabSelected')[0];
var b = a.getElementsByClassName("child")[0].innerHTML;
alert(b); //assume b is my extracted text
document.querySelectorAll() is often a better function to use when trying to query the DOM for elements. It essentially allows you to use CSS selector syntax to perform more complicated queries (much like jQuery) and has support down to IE8.
In your case:
var spanElement = document.querySelectorAll(".secondaryTabSelected span")[0];
alert(spanElement.innerText);
Should perform what you are trying to achieve.
There are two issues in your code:
td need to be nested in in node, otherwise the browser will remove the tag.
you haven't put child as a class in html
You can either remove the first line and add class direclty in your target node or use childNodes instead
var a = document.getElementsByClassName('secondaryTabSelected')[0];
console.log(a);
var b = a.childNodes[1].innerHTML
console.log(b);
<div class="secondaryTabSelected" title="Pace">
<span tabindex="0">Pace</span>
</div>

Make jQuery Search Filter use a Data attribute instead of whole DIV content

I have a KanBan board style app that shows Order records. I am trying to implement a Search filter using JavaScript and jQuery. THe goal is to filter out and hide all records that do not match the search number with the Order Number on a record.
So far I have a working example however I feel it can be improved possibly?
Here is my working JSFiddle Demo: http://jsfiddle.net/jasondavis/d7hj0ssv/1/
So basically it;s very simple....
It when the search form is submitted, it hides all Order records
It then uses this line $('.box:contains("'+txt+'")').show(); where txt is the search term. So after hiding all records, it display: block on any DIVs that match the search term.
$('.box:contains("'+txt+'")') is where my concern is. I believe it searches the whole entire Order record DIV for a matching string?
Each Order DIV looks like this code below so $('.box:contains("'+txt+'")') is searching this whole entire block of content for each order I believe which just looks bad performance wise!...
<div class="box card-record ui-sortable-handle" data-order-id="5430" data-order-number="100005054" data-order-item-id="145" style="display: block;">
<div class="alert-message warning">
<div class="ordernumber">Order #100005054</div>
<div class="orderid">Order ID: 5430</div>
<div class="itemid">Item #145</div>
<div>Date Created: 2015-06-23 00:27:22</div>
<div>Date Modified: 2015-06-23 00:27:22</div>
<div>some order data here</div>
View Order Item
</div>
</div>
In the DIV HTML above you might notice that each Order record also has a data attribute data-order-number="100005054" which I think might be better to use for the search if possible?
Below is my jQuery JavaScript code that handles the Search input and filtering out the DIVs based on the search term:
$(function() {
// Search filter to hide and show order cards mtching the search order number
$('#search').click(function(){
$('.box').hide();
var txt = $('#search-criteria').val();
$('.box:contains("'+txt+'")').show();
});
$('#searchclear').click(function(){
$('.box').show();
$('#search-criteria').val('');
});
});
If the search field is the order-number then yes, using the data-attribute would greatly improve your apps response time. You would use the jQuery .filter(function) method:
$('#search').on('click', function() {
$('.box').hide().filter(function() {
return $(this).data('order-number') == $('#search-criteria').val().trim();
}).show();
});
DEMO
If you want to target the div with that data, you can use the attribute selector syntax. This isn't terribly performant, but it should be faster than the :contains pseudo selector.
$('.box[data-order-number="'+txt+'"]').show();
or
$('.box[data-order-id="'+txt+'"]').show();
Some of your elements don't seem to have data-order-number in the fiddle, so I've used the id for the example. Not sure on the specifics between the two.
http://jsfiddle.net/47m7p2am/
The other option is to generate unique IDs or shared classes.
id="order-number-100005054" class="order-id-5418"
This would be much faster to look up, and the ideal solution if you can edit the HTML output.
Something like:
$('#order-number-' + txt).show();

What is the best way of displaying conditional content in ng-repeat loop

I am using this a lot and I feel like I'm doing it wrong.
in ng-repeat, I want to show some part, if the condition is right but I don't want it to be in loop, I need to display it when I want and where I want.
for example:
$scope.selectedItemId is defined and changed from javascript dynamically.
<div ng-repeat=“item in items”>
<div>{{item.name}}</div>
<div ng-if=“selectedItemId==item.id”>{{item.condition}}</div>
</div>
At the example, instead of item.condition, it may be a rest result or a directive too.
It looks like it checks for every item in the loop. I want to put the content to there dynamically. When user clicks a button which sets the selected item, I want it to show the content of it where ng-if is now.
You can do it without the loop. For example, your html:
<button ng-click="setItem('uniq-id')">click me</button>
<div>{{selectedItem.condition}}</div>
And js (I'm use lodash for simplification):
$scope.setItem = function (id) {
$scope.selectedItem = _.find($scope.items, {id: id});
};

Find similar HTML parts

I have following (simplified) HTML code and want to split it into similar parts:
<input id="checkbox1"><label><br>
<input id="checkbox2"><label><br>
<input id="checkbox3"><label><br>
The result for this should be <input><label><br>. But the problem is, I need a bulletproof solution, which would for example return <div><p><input></p><p><label></p></div> from the following HTML:
<div><p><input id="checkbox1"></p><p><label></p></div>
<div><p><input id="checkbox2"></p><p><label></p></div>
<div><p><input id="checkbox3"></p><p><label></p></div>
Any idea how to find such a pseudo parent element in JavaScript/jQuery?
Like Rory McCrossan figured out, this is indeed used for a templates system. The user defines one row in this template, like <input id="checkbox1"><label><br> which is then displayed x times on the screen. I need this template in my JS code, but there is unfortunately no direct access to the user template, so my idea was to figure out which HTML parts look similar and the splitting them to get the template back.
As a partial solution, you could consider identifying the closest common ancestor for an input label pair, and using this as the repeating element:
var collection = $('');
$('input').each(function() {
collection = collection
.add($(this)
.parents(':has(label)')
.filter(function() {
return $(this).siblings().length == $(this).siblings(this.tagName).length;
}));
});
console.log(collection);
This presupposes each label input pair has a common parent element, and so doesn't work for your first case.

Categories