Find similar HTML parts - javascript

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.

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.

Match/group HTML elements by their data attributes values

In the HTML I have multiple elements that are grouped by data attributes, but these attributes don't necessarily have the same parent:
Example:
<span data-toggle-trigger="1">Resources</span>
<p>......<p>
<span data-toggle-trigger="2">Alpha</span>
<div data-toggle-container="1"></div>
<p>......<p>
<span data-toggle-trigger="3">Beta</span>
<div data-toggle-container="2"></div>
<div data-toggle-container="3"></div>
The used attributes are:
data-toggle-trigger` and `data-toggle-container
The behavior I need:
When someone click on data-toggle-trigger something happens on data-toggle-container (like show/hide).
To get them:
triggers = document.querySelectorAll(['data-toggle-trigger']);
container = document.querySelectorAll(['data-toggle-container']);
It looks like I have two options:
To get all of them and try to group them
To get only triggers and than search after that for containers
I'm inclining for 1), but I don't know what the best option is to group.
My naive approach is to think/use 2 for nested loops and loop and compare value, but I don't know if is the best option. So I'm looking for some opinion regarding a good approach.
Important - I'm using pure JavaScript, no ECMAScript 6 syntax sugar (because of other stuff).
This is opinion-based, but I think the most efficient solution is to have only one event listener, possibly on <body>, and if the target has .dataset.toggleTrigger, then show/hide all matching elements, i.e., querySelectorAll('[data-toggle-container="' + x + '"]') in a loop.
I would add classes to manage your triggers and containers. Here is example: Fiddle.
In this snippet I add text every time you click on a trigger.
function myFunction(numberOfTriggerClicked) {
var element = document.querySelectorAll("[data-toggle-container='"+numberOfTriggerClicked+"']")[0];
element.innerText += " NEW TEXT";
}

BootstrapToggle switch conditionally switch state

I'm trying to use bootstraptoggle in one of my pages. The initial state is off / disabled.
The page loads several boolean values and stores them as hidden text. Then I have a script which looks them up via their IDs. Upon that hidden text it should toggle the slider.
I was able to get the hidden text and make the conditional check but I'm not able to toggle the slider for some reason.
Here is my code:
$(document).ready(function () {
var flags = [];
var userID = '',
toggleSlider = '';
flags = document.querySelectorAll('*[id^="activeFlag_"]');
flags.forEach(function (flag) {
userID = flag.id.split('_')[1];
// This is where i search for the hidden text
if (flag.firstChild.data == 'True') {
// Nothing works here.
$('#activeToggle_' + userID).bootstrapToggle('toggle');
}
});
});
And this is the html code that I need to work with:
<p id="activeFlag_#user1">#item.activeFlag</p>
<div class="checkbox">
<label>
<input id="activeToggle_user1" type="checkbox" data-toggle="toggle" data-on="Enabled" data-off="Disabled">
</label>
</div>
Your code is too opaque without any data example.
However one thing could be a cause of its problem:
if (flag.firstChild.data == 'True') {
Try to replace it with:
if (flag.firstElementChild.data == 'True') {
Here you could find explanation:
The firstChild property returns the first child node of the specified node, as a Node object.
The difference between this property and firstElementChild, is that firstChild returns the first child node as an element node, a text node or a comment node (depending on which one's first), while firstElementChild returns the first child node as an element node (ignores text and comment nodes).
Note: Whitespace inside elements is considered as text, and text is considered as nodes (See "More Examples").
Update after example code was added
For the example code you provided, you should change the split argument:
userID = flag.id.split('_')[1];
to:
userID = flag.id.split('_#')[1];
Thanks to twain for initial jsfiddle. I have updated it accordingly: jsfiddle
I guess the problem is, that the following part does not use the correct id for the toggle $('#activeToggle_' + userID).bootstrapToggle('toggle');
Your html ID is activeToggle_user1, but the js part above will probably resolve to #activeToggle_1. So the text user is missing here.
I created a working fiddle here: https://jsfiddle.net/pbcrh5d2/
Ok, for some reason asp.net and javascript have a problem with coping together. I used asp.net to provide javascript to build the strings.
So I switched to the raw id that is used in the table.

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();

How to get a DOM Element from a jQuery selector?

I'm having an impossibly hard time finding out to get the actual DOMElement from a jQuery selector.
Sample Code:
<input type="checkbox" id="bob" />
var checkbox = $("#bob").click(function() { //some code } )
and in another piece of code I'm trying to determine the checked value of the checkbox.
if ( checkbox.eq(0).SomeMethodToGetARealDomElement().checked )
//do something.
And please, I do not want to do:
if ( checkbox.eq(0).is(":checked"))
//do something
That gets me around the checkbox, but other times I've needed the real DOMElement.
You can access the raw DOM element with:
$("table").get(0);
or more simply:
$("table")[0];
There isn't actually a lot you need this for however (in my experience). Take your checkbox example:
$(":checkbox").click(function() {
if ($(this).is(":checked")) {
// do stuff
}
});
is more "jquery'ish" and (imho) more concise. What if you wanted to number them?
$(":checkbox").each(function(i, elem) {
$(elem).data("index", i);
});
$(":checkbox").click(function() {
if ($(this).is(":checked") && $(this).data("index") == 0) {
// do stuff
}
});
Some of these features also help mask differences in browsers too. Some attributes can be different. The classic example is AJAX calls. To do this properly in raw Javascript has about 7 fallback cases for XmlHttpRequest.
Edit: seems I was wrong in assuming you could not get the element. As others have posted here, you can get it with:
$('#element').get(0);
I have verified this actually returns the DOM element that was matched.
I needed to get the element as a string.
jQuery("#bob").get(0).outerHTML;
Which will give you something like:
<input type="text" id="bob" value="hello world" />
...as a string rather than a DOM element.
If you need to interact directly with the DOM element, why not just use document.getElementById since, if you are trying to interact with a specific element you will probably know the id, as assuming that the classname is on only one element or some other option tends to be risky.
But, I tend to agree with the others, that in most cases you should learn to do what you need using what jQuery gives you, as it is very flexible.
UPDATE: Based on a comment:
Here is a post with a nice explanation: http://www.mail-archive.com/jquery-en#googlegroups.com/msg04461.html
$(this).attr("checked") ? $(this).val() : 0
This will return the value if it's checked, or 0 if it's not.
$(this).val() is just reaching into the dom and getting the attribute "value" of the element, whether or not it's checked.

Categories