I have the below url
<h1 id="header_2" title="mytitle" data-id="header_title" class="sampleclass " xpath="1">mytitle<span aria-label="sometest" class="sampleclass ">- Saved</span></h1>
Based in the id(header_2)I wabt to fetch title.
My id may also contains like this id="header_mdfa3fad" but for sure after "_" it is numeric.HOw do I write querySelector for it
You can apply regex to filter like this
var divs = [].slice.call(document.querySelectorAll("[id^='header_']")).filter(function(el){
return el.id.match(/^header_[0-9]+/i);
});
console.log(divs);
<div id="header_1"></div>
<div id="header_2"></div>
<div id="header_3"></div>
<div id="header_abc"></div>
<div id="header_xyz"></div>
You can use this solution:
const headers = document.querySelectorAll("[id^='header_']");
const titles = [];
headers.forEach((header) => titles.push(header.getAttribute('title')));
// Do something you want with titles array
If I understand you correctly, try something like this:
#select h1 elements with id attribute whose value begins with "header"
headers = document.querySelectorAll("[id^='header_']");
#loop through the elements and extract the part of the attribute value following "_"
for (let header of headers) {
target = header.getAttribute('id').split('_')[1]
#check for the presence of a digit
if (/\d/.test(target)) {
console.log(header.getAttribute('title'))
}
}
Related
How to add data-name dynamically to an element but not dataset what add data=" ", but only data?
Something like this:
<div class="battle-screen__bullet" data-bullet></div>
const el = document.querySelector('div.battle-screen__bullet')
el.dataset.bullet_new = ''
dom will become
<div class="battle-screen__bullet" data-bullet data-bullet_new></div>
Used below HTML & JS to get first character of string and display. Manually its possible to calculate and get value.
When its goes to dynamic and name with only first and last name not sure how to calculate character position after space and get first character of word.
$('.splitname .fname').html(name.charAt(0));
$('.splitname .mname').html(name.charAt(8));
$('.splitname .lname').html(name.charAt(16));
<div class="name">Desmond Patrick Reymond</div>
<div class="splitname">
<span class="fname">D</span>
<span class="mname">P</span>
<span class="lname">R</span>
</div>
Use this logic:
"Desmond Patrick Reymond".split(" ").map(name => name[0])
// => ["D", "P", "R"]
If you need to modify the HTML programmatically, do:
let s = $('.name').text();
s.split(" ").map(name => $('.splitname').append(name[0]))
(It's not really good practice to use map for side effects though; you may choose to use forEach instead.)
You can simply use match() function and a simple ReGex to get the dynamic text data with spaces without having to check for charAt()
//get text
let name = $('.name').text();
//match the spaces
var matches = name.match(/\b(\w)/g); // [D,P,R]
//join the chars - if needed
var joinChar = matches.join(''); // DPR
//show the split name
$('.splitname').text(joinChar);
console.log(matches ) // [D,P,R] //Array
console.log(joinChar) //DPR //String
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="name">Desmond Patrick Reymond</div>
<div class="splitname"></div>
You can make use of Array#split and Array#map and Array#join as in the demo below. Result will be:
<div class="splitname">
<span class="fname">D</span>
<span class="mname">P</span>
<span class="lname">R</span>
</div>
//Classes for the initials
const classes = ['fname', 'mname', 'lname'];
//Where to put the initials
$('.splitname')
//make HTML generated content of
.html(
//Get Full Name
$('.name').text()
//Break into names array
.split(' ')
//Get initial of each name
.map(name => name.charAt(0))
//Wrap each initial in a span element
.map((initial,index) => `<span class="${classes[index]}">${initial}</span>`)
//Join all span elements array into string
.join('')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="name">Desmond Patrick Reymond</div>
<div class="splitname"></div>
This is my first question at stack overflow
i just wanted to know a simple solution for the following case
<div *ngFor="let d of w.event">
<div class="date" id="d.date" >
<p>
<span style="font-size:1.75em">{{d.date | date:'dd'}}</span>
<br>
<strong> {{d.date | date:'EEE'}}</strong>
</p>
</div>
the looped div can have the same id
I just want to display the first div with a particular date and ignore the rest
can this be achieved with CSS or JavaScript
You can't use the same id on two elements. It's one of the few restrictions on ids.
You can use a class:
<div class="show">Yes</div> <div class="show">No</div>
...and then show either the first or second by using index 0 or index 1 after getting a list of matching elements:
var list = document.querySelectorAll(".show");
list[0].style.display = "none"; // Hides the first one
// or
list[1].style.display = "none"; // Hides the second one
Some other thoughts:
1. Rather than using style.display as I did above, you might add a class that hides the element.
2. You might use separate ids (or classes) for the elements so you don't need to index, e.g.:
<div id="show-yes">Yes</div> <div id="show-no">No</div>
then
document.getElementById("show-yes").style.display = "none";
// or
document.getElementById("show-no").style.display = "none";
On all browsers in my experience, you can do the first thing above (with querySelectorAll) with your invalid HTML with a selector like "[id=show], but don't. Fix the HTML instead.
In your question update, you show:
<div *ngFor="let d of w.event">
<div class="date" id="d.date" >
...
You've said you're aware of the fact you can't have multiple elements with the same id, so why code that? You can easily give them unique ids:
<div *ngFor="let d of w.event; let i = index">
<div class="date" id="d.date{{i}}" >
...
First of all, in HTML ID is a unique selector so one ID can be associate with only one element. if you want to achieve your desired functionality you have to assign different id for both DIV. and use javascript to hide and show DIV
<div id="showYes">Yes</div> <div id="showNo">No</div>
If you want to show one at a time you can go with *ngIf , as it will show only one at a time
<div id="show" *ngIf='your_status'>Yes</div>
<div id="show" *ngIf='!your_status'>No</div>
After your question update , you can create custom filter that will only return unique date , so only first unique date will be shown
// CREATE A PIPE FILTER :
import { Pipe, PipeTransform } from '#angular/core';
#Pipe({name: 'checkUniqueDate'})
export class UniqueDatePipe implements PipeTransform {
transform(dataArray) {
let dates = [];
return dataArray.filter(data => {
return if(dates.indexOf(data.date) === -1) {
dates.push(data.date);
return true;
} else {
return false;
}
});
}
}
// TEMPLATE SIDE :
<div *ngFor="let d of (w.event | checkUniqueDate )">
Add the date in class also, then you can try below code
.YOUR_DATE{
display:none
}
.YOUR_DATE:first-child{
displany:inline
}
I have a bunch of Custom Elements that begin with 'food-cta-'. I am looking for a way in JavaScript/jQuery to be able to select these elements. This is similar to how I can use $('*[class^="food-cta-"]') to select all the classes that start with food-cta-. Is it possible to do a search for elements that start with 'food-cta-'?
Note that I will be injecting this search onto the page, so I won't have access to Angular.
Example of Custom Elements:
<food-cta-download>
<food-cta-external>
<food-cta-internal>
EDIT: The code I am looking at looks like:
<food-cta-download type="primary" description="Download Recipe">
<img src="">
<h2></h2>
<p></p>
</food-cta-download>
The app uses AngularJS to create Custom Elements which I believe is called Directives.
You can use XPath with the expression
//*[starts-with(name(),'food-cta-')]
Where
//* is wildcard for all nodes
starts-with() is a XPath function to test a string starts with some value
name() gets the QName (node name)
and 'food-cta-' is the search term
Pass it into document.evaluate and you will get a XPathResult that will give you the nodes that were matched.
var result = document.evaluate( "//*[starts-with(name(),'food-cta-')]", document, null, XPathResult.ANY_TYPE, null );
Note you can use any node as the root, you do not need to use document. So you could for instance replace document with the some div:
var container = document.getElementById("#container");
var result = document.evaluate( "//*[starts-with(name(),'food-cta-')]", container, null, XPathResult.ANY_TYPE, null );
Demo
let result = document.evaluate( "//*[starts-with(name(),'food-cta-')]", document, null, XPathResult.ANY_TYPE, null );
let nodes = [];
let anode = null;
while( (anode = result.iterateNext()) ){
nodes.push( anode.nodeName );
}
console.log(nodes);
<div id="container">
<br>
<food-cta-download type="primary" description="Download Recipe">
<img src="">
<h2></h2>
<p></p>
</food-cta-download>
<span>Some span</span>
<food-cta-something>
<img src="">
<h2></h2>
<p></p>
</food-cta-something>
<div>In between
<food-cta-sub>
<img src="">
<h2></h2>
<p></p>
</food-cta-sub>
</div>
<food-cta-hello>
<img src="">
</food-cta-hello>
<food-cta-whattt>
</food-cta-whattt>
</div>
Try this..
let customElements = $('*')
.filter((index,element) => /FOOD-CTI-/.test(element.tagName));
Note, .tagName should return the result in uppercase. This should get you a jQuery object of the elements you want. It will traverse the entire DOM though. It'll be slow.
This uses the "all selector".
Caution: The all, or universal, selector is extremely slow, except when used by itself.
You can traverse less then entire dom too, by specifying something like $("body *"). Not sure where you have put the Custom Elements, and where they're allowed.
As an aside, I wouldn't use Custom Elements, microformats are a better idea at least now, they're also better supported, and they're less likely to change.
You probably have to just go to the elements in question and check if their tagName begins with that given string...
var myPrefix = "mycustom-thing-";
$("body").children().each(function() {
if (this.tagName.substr(0, myPrefix.length).toLowerCase() == myPrefix) {
console.log(this.innerHTML); // or what ever
}
})
https://jsfiddle.net/svArtist/duLo2d0z/
EDIT: Included for efficiency's sake:
If you can predict where the elements will be, you can of course specify that circumstance.
In my example, the elements in question were direct children of body - so I could use .children() to get them. This would not traverse lower levels.
Reduce the need for traversal by the following:
Start on the lowest needed level ($("#specific-id") rather than $("body"))
If the elements are all to be found as direct children of a container:
Use $.children() on the container to obtain just the immediate children
Else
Use $.find("*")
If you can tell something about the containing context, filter by that
For example $("#specific-id").find(".certain-container-class .child-class *")
Why not extend jquery selectors?
$(':tag(^=food-cta-)')
Would be possible with the following implementation:
$.expr[':'].tag = function tag(element, index, match) {
// prepare dummy attribute
// avoid string processing when possible by using element.localName
// instead of element.tagName.toLowerCase()
tag.$.attr('data-tag', element.localName || element.tagName.toLowerCase());
// in :tag(`pattern`), match[3] = `pattern`
var pattern = tag.re.exec(match[3]);
// [data-tag`m`="`pattern`"]
var selector = '[data-tag' + (pattern[1] || '') + '="' + pattern[2] + '"]';
// test if custom tag selector matches element
// using dummy attribute polyfill
return tag.$.is(selector);
};
// dummy element to run attribute selectors on
$.expr[':'].tag.$ = $('<div/>');
// cache RegExp for parsing ":tag(m=pattern)"
$.expr[':'].tag.re = /^(?:([~\|\^\$\*])?=)?(.*)$/;
// some tests
console.log('^=food-cta-', $(':tag(^=food-cta-)').toArray());
console.log('*=cta-s', $(':tag(*=cta-s)').toArray());
console.log('food-cta-hello', $(':tag(food-cta-hello)').toArray());
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<br>
<food-cta-download type="primary" description="Download Recipe">
<img src="">
<h2></h2>
<p></p>
</food-cta-download>
<span>Some span</span>
<food-cta-something>
<img src="">
<h2></h2>
<p></p>
</food-cta-something>
<div>In between
<food-cta-sub>
<img src="">
<h2></h2>
<p></p>
</food-cta-sub>
</div>
<food-cta-hello>
<img src="">
</food-cta-hello>
<food-cta-whattt>
</food-cta-whattt>
</div>
This supports a pseudo-CSS-style attribute selector with the syntax:
:tag(m=pattern)
Or just
:tag(pattern)
where m is ~,|,^,$,* and pattern is your tag selector.
For My projet i need to know how i can transmit some variables to a async url. The plugin I use is a simple popover that call a URL to fetch html data and show the result.
I need to use $(this) because i have many URls with the same class. I must transmit the data-type (ex: picture) and the id of the product (data-id).
My link = Check this out
What i want to do (but it doesn't work) :
$('.product').webuiPopover({
var productType = $(this).data('type');
var id = $(this).data('id');
type:'async',
url:'/api/popover/'+ productType +'/'+id
});
Is it possible ? How i can do that ?
Note : here is the plugin I use (github : sandywalker/webui-popover)
You have to initialize webuiPopover for each .product element individually. Do something like this:
$('div').each(function(index, el){
$(el).webuiPopover({
title: $(el).data('foo') // Direct access to the data attributes of this element
})
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/jquery.webui-popover/1.2.5/jquery.webui-popover.min.js"></script>
<div data-foo="First title">Hello</div>
<div data-foo="Second title">Goodbye</div>
If you want to add variable then you can do it like:
$('.product').each(function(i,t){
var t = $(t);
t.webuiPopover({
type:'async',
url:'/api/popover/'+ t.data('type') +'/'+ t.data('id')
});
});