How to get the unique selector of elements [duplicate] - javascript

This question already has answers here:
What is the path in the html dom for a selected element? [duplicate]
(2 answers)
Closed 9 years ago.
I am doing an editor where when user clicks a text or anything in the html document, I get it changed and record the changes in the database. It is a widget I am doing. Thus this is my question. Suppose I have an html element of the following structure:
<html>
<table>
<tr>
<td>Apple</td>
<td>Pear</td>
</tr>
<tr>
<td>Chicken</td>
<td>Beef</td>
</tr>
</table>
<div id="one">
<p>Red</p>
<p>Orange</p>
</div>
<div class="two">
<p>Green</p>
<p>Purple</p>
</div>
<div class="two">
<p>Black</p>
<p>Blue</p>
</div>
</html>
When user clicks Apple, the unique path is (Jquery):
table:eq(0)>tr:eq(0)>td:eq(1)
Suppose user clicks Red, the unique path is (Jquery):
div#one:eq(o) > p:eq(0)
Is there any plugin readily available to uniquely identify the selectors?
Currently I am using this function:
function getUniquePath2(node){
var parentEls = node.parentsUntil('[id]').add( node.closest('[id]') )
.map(function () {
return this.tagName + (this.id ? '#' + this.id : "");
})
.get().join(">");
return parentEls;
}
However the above won't support and I have been researching for 4 days and I don't get an idea of how I should do it. The reason I am doing this because I want to track the user changes and change the elements as per the draft the user has made. The issue is, some elements do not have id's and the xpath conflicts with other elements. For instance if I want to change Green. How would it be unique anymore?

What about something like this ?
var getUniquePath = function( node ) {
var parts = [ ];
$( node ).parents().each( function( index, element ) {
parts .push( element.tagName + '[' + $(element).index() + ']' );
});
return parts.join( '', parts.reverse() );
}

Related

How to append text/html aside other jquery tags in JQuery

I am trying to design a calendar component and the html for the section is:
<th id="thNow">July<span class="scrollArrow"><img src="/UpDownArrow.png" /></span>, 2022<span class="scrollArrow"><img src="/UpDownArrow.png" /></span></th>
In JQuery (3 if it matters), the code I'm attempting with it is:
var thNow = $("<th></th>", { id: "thNow" })
.html(sMonth)
.append(
$("<span></span>", { "class": "scrollArrow" })
.append(
$("<img />", { "src": "/UpDownArrow.png" })))
.html(", ")
.html(sYear)
.append(
$("<span></span>", { "class": "scrollArrow" })
.append(
$("<img />", { "src": "/UpDownArrow.png" })));
even though I know that won't work - How do I effectively piece together the string of the Month name like with .html(), an img tag, the text ", " and the year, and another image tag - This Jquery code just replaces the Month name with the year and the image tag.
Do I need to wrap each of the text in a span/div or something? Eventually (after I add the code that is), the month name and year will be links to select a month out of all the months and a year out of all the years like one might see in a date picker but this is more than just a date picker.
It's for my own personal calendar to merge my work and home calendars to make a sort of calendly site for myself but which will use google apis to query my google calendar and Office APIs to query my work calendar and people (or I) can add events to it as well.
Is there a way to do what I want or do I need to definitely wrap each of the text things in a tag of some sort?
The problem with your code is because you're calling html() to add the , and the year strings. This is overwriting all the previous HTML you appended to the element. Use append() instead.
In addition, the HTML you clone includes an id, as noted by #zer00ne in the comments below. This will mean that your HTML becomes invalid as id attributes must be unique within the DOM. Change this to a class instead.
let sMonth = 'July';
let sYear = '2022';
var thNow = $("<th />", {
class: "thNow"
}).html(sMonth)
.append(
$("<span />", { class: "scrollArrow" }).append(
$("<img />", { src: "/UpDownArrow.png" })
)
)
.append(" , " + sYear)
.append(
$("<span />", { class: "scrollArrow" }).append(
$("<img />", { src: "/UpDownArrow.png" })
)
);
thNow.appendTo('table tr');
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<table>
<tr>
<th class="thNow">
July
<span class="scrollArrow"><img src="/UpDownArrow.png" /></span> , 2022
<span class="scrollArrow"><img src="/UpDownArrow.png" /></span>
</th>
</tr>
</table>
However it's worth noting that building HTML through JS/jQuery is not an ideal solution. It leads to very verbose code that takes some conscious effort to understand and is difficult to maintain.
The far better approach would be to store the HTML as a template within the HTML page. Then you can just use jQuery to clone that template and update any labels within it.
This pattern has the benefit of separating the HTML and JS concerns (ie. the developer who knows HTML can easily update the template without needing to understand how the JS works), and also allowing for much simpler JS code. Try this:
let addHeader = ($target, month, year) => {
let html = $('#th-template').html()
.replace('{{month}}', month)
.replace('{{year}}', year)
$target.append(html);
}
$('#add-header').on('click', () => addHeader($('table tr'), 'July', '2022'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<button type="button" id="add-header">Add header</button>
<template id="th-template">
<th class="thNow">
{{month}}
<span class="scrollArrow"><img src="/UpDownArrow.png" /></span> , {{year}}
<span class="scrollArrow"><img src="/UpDownArrow.png" /></span>
</th>
</template>
<table>
<tr>
<th class="thNow">
July
<span class="scrollArrow"><img src="/UpDownArrow.png" /></span> , 2022
<span class="scrollArrow"><img src="/UpDownArrow.png" /></span>
</th>
</tr>
</table>

Trouble setting the HTML of a variable in JQuery

What I've done is loaded some HTML from a file and I am attempting to modify some elements within that HTML.
The initialization looks like this:
var id = player_info["ID"];
$("#main_container").append(
$("<div />").attr({class: "player_container", id: "player_" + id}).css("display", "none")
);
// Add all information to the player container
var player_container = $("#player_" + id);
player_container.load("player_layout.html");
With player_layout.html looking like this:
<div class="player_name">
</div>
<div class="player_chips">
Chips:
<br/>
<span class='bidding'></span>/<span class='chips'></span>
</div>
<div class="player_stats">
Wins / Losses
<br/>
<span class="wins"></span>/<span class="losses"></span>(<span class="total_games"></span>)
<br/><br/>
Chips Won / Chips Lost
<br/>
<span class="chips_won"></span>/<span class="chips_lost"></span>
</div>
<button class="player_won">Player Has Won</button>
I then want to modify some of the elements, specifically classes. An example of the way I was initially doing this is:
player_container.find(".player_name").text(player_info['username']);
This wasn't working so I then tried to switch find with children and text with html but that didn't seem to work. I then tried this:
$('> .player_name', player_container).html(player_info['username']);
but that also didn't work. I understand that I can use DOM to grab the childNodes and compare the class names but there are a lot of classes that need modifying and I'd also like to know if this is possible in JQuery. Thanks in advance for any help.
You need to use complete callback method of .load()
var player_container = $("#player_" + id);
player_container.load("player_layout.html", function(){
player_container.find(".player_name").text(player_info['username']);
});

How to get the id's within the html tags [duplicate]

This question already has answers here:
How to get an array of attribute value from elements in a jQuery object
(3 answers)
Closed 7 years ago.
I'm trying to do a screen scraping on twitter, i'm using Jsoup library and this is a sample of html code of the page :
<div class="stream permalink-stream">
<ol id="stream-items-id" class="stream-items js-navigable-stream">
<li id="stream-item-tweet-692459333712347137" class="js-stream-item stream-item stream-item expanding-stream-item " data-item-type="tweet" data-item-id="692459333712347137">
<li id="stream-item-tweet-692470683348123649" class="js-stream-item stream-item stream-item expanding-stream-item " data-item-type="tweet" data-item-id="692470683348123649">
<li id="stream-item-tweet-692489785978523648" class="js-stream-item stream-item stream-item expanding-stream-item " data-item-type="tweet" data-item-id="692489785978523648">
</ol>
<ol class="hidden-replies-container"></ol>
</div>
what I'm trying to do first is to get all id's of the li tags in the web page, to use them after in a loop to get the text inside each li tag.
the result I want, is something like :
id1 = stream-item-tweet-692459333712347137
id2 = stream-item-tweet-692489785978523648
id3 = stream-item-tweet-692489785978523648
I've tried something like with Jsoup, but it doesn't work :
Elements scriptElements = doc.getElementsByTag("li");
for (Element element :scriptElements ){
for (DataNode node : element.dataNodes()) {
System.out.println(node.getWholeData());
}
}
thanks !
here's an example:
$('ol').find('li').each(function(k,v)
{
alert('id = ' + $(this).attr('id'));
});

Get child elements within casper.each

Using CasperJS 1.1 with the following codes, I'm able to fetch useful DOM html from web page.
casper.each(c.getElementsInfo(xpath), function(casper, element, j) {
var html = element["html"].trim();
if(html.indexOf('Phone') > -1) {
// what should I put here?
}
});
However, I want to access & obtain the child elements of the element. How can I achieve this? Element's HTML source (a.k.a the value of html) is as follow:
Loop 1
<div class="fields">
Phone
</div>
<div class="values">
12345678 (Mr. Lee) </div>
Loop 2
<div class="fields">
Emergency Phone
</div>
<div class="values">
23456789 (Emergency)
</div>
Loop 3
<div class="fields">
Opening Hours
</div>
<div class="values">
9:00am-6:30pm(Weekday) /
Close on Sundays and Public Holidays(Can be booked)(Holiday)
</div>
Loop 4
<div class="fields">
Last Update
</div>
<div class="values">
11/06/14 </div>
The above HTML is badly formatted, and contains a lot of whitespaces.
The data I wanted to fetch is:
Phone: 12345678
Emergency Phone: 23456789 (Emergency)
Opening Hours: 9:00am-6:30pm(Weekday) / Close on Sundays and Public Holidays(Can be booked)(Holiday)
Last Update: 11/06/14
Tried RegEx, but the RegEx is too complicated.
I don't recommend doing this with regular expressions. It can be easily done with some selectors, but it has to be done in the page context (inside of the evaluate() callback), because DOM nodes cannot be passed to the outside.
CasperJS provides a helper function for matching DOM nodes by XPath with __utils__.getElementsByXPath() through the ClientUtils module that is always automatically inserted. The result of that function is an array, so the normal forEach() pattern applies. DOM nodes can be used as context nodes for selecting child elements with el.querySelector(".class").
var info = casper.evaluate(function(xpath){
var obj = {};
__utils__.getElementsByXPath(xpath).forEach(function(el){
obj[el.querySelector(".fields").textContent.trim()] =
el.querySelector(".values").textContent.trim();
});
return obj;
}, yourXPathString);
If you want to select elements based on a CSS selector use the following:
var info = casper.evaluate(function(cssSelector){
var obj = {};
__utils__.findAll(cssSelector).forEach(function(el){
obj[el.querySelector(".fields").textContent.trim()] =
el.querySelector(".values").textContent.trim();
});
return obj;
}, yourCssSelector);

Accessing html elements from a div tree with javascript

I need to access title value from some img elements but these elements are deeply implemented in a div tree and after that into some tables.
Let me explain why I need them:
I use a portal where I have information regarding circuits from a network. This portal contains some locations with a few rows (2-3 usually -> circuits for that location). Each row starts with an img element and it can have a few values on title attribute. If the title value is != "No alarms" then I have to take all data from that row and I want to show them via a pop up notification on the bottom right corner near clock.
Below you have a screenshot for how are the html elements organized (for all locations).
http://imageshack.com/a/img661/962/ErjQOt.png
Below you have a screenshot for how is a location organized:
http://imageshack.com/a/img661/7453/QAP5oM.png
If title attribute == "Warning", for example, I have to take the data from the next td's in the same table. Each td has another div without id. Firsts 2 td's on each table have another element inside div: img on first one and a href on the second one.
I'm drawing the tree to show you exactly how are the html elements organized.
<table class="x-grid3-row-table">
<tbody>
<tr>
<td> <!--first td, this contains div->img-->
<div class="x-grid3-cell-inner x-grid3-col-0">
<img .... title="No alarms">
</div>
</td>
<td> <!--second td, this contains div->a href-->
<div class="x-grid3-cell-inner x-grid3-col-1">
<a href...>
</div>
</td>
<td> <!--3rd td, this contains div->string:Text1-->
<div class="x-grid3-cell-inner x-grid3-col-2">Text1</div>
</td>
<td> <!--4th td, this contains div->string:Text2-->
<div class="x-grid3-cell-inner x-grid3-col-2">Text2</div>
</td>
...
</tr>
</table>
Location-1 has 3 circuits, this means 3 tables. The above table is inserted in a div (div class="x-grid3-row x-grid3-row-first" from screenshot2). There are 2 more tables after this one on another div's (div class="x-grid3-row x-grid3-row-alt" & div class="x-grid3-row" from screenshot2) and I have to check the title attribute for each table.
Now my question is how to get the title attribute from each table on the same location? and if the title is != "No alarms" how can I get data from the next td's in that table?
Maybe I can use a loop for all 12 locations or maybe I can get them one by one. This is no big deal because there are only 12 locations but the nasty thing is inside each location to get info from each circuit.
I think there should be a syntax like this to reach each html elements and to get the right value.
var title = $('#ext-gen15-gp-location-1-bd table[0] td[0] img').attr('title');
var title = $('#ext-gen15-gp-location-1-bd table[0] td[1] div[0]').attr('innerHTML');
....
var title = $('#ext-gen15-gp-location-1-bd table[1] td[0] img').attr('title');
var title = $('#ext-gen15-gp-location-1-bd table[1] td[1] div[0]').attr('innerHTML');
...
var title = $('#ext-gen15-gp-location-9-bd table[0] td[0] img').attr('title');
var title = $('#ext-gen15-gp-location-9-bd table[0] td[1] div[0]').attr('innerHTML');
...
...and so on. I'm sure that this syntax is not correct but I think there should be a way to get that data.
I hope that now is explained better then the first time.
EDIT
Guys, thank you very much. You help me a lot. Your codes are working.
Anyway, I just want to ask you something else.
After 3 minutes the whole table is refreshing and I can't find a way to reload the function after that. When the content is refreshing, div ext-gen24 remains empty and after that is refilled with the content:
When is refreshing:
<div class="x-grid3-body" style="width: 1877px;" id="ext-gen24"></div>
After refresh is completed
<div class="x-grid3-body" style="width: 1877px;" id="ext-gen24">content</div>
Can you help me with a function you think it should work in this case ?
You'll need loop through multiple stages of the html: groups, tables, and columns:
var groups = $('.x-grid-group-body'); //hopefully all the '#ext-gen15-gp-location-X-bd' div have 'x-grid-group-body' as the class
groups.each(function () {
var tables = $(this).find('table');
tables.each(function () {
var columns = $(this).find('td');
var image = $(columns[0]).find('img');
var title = image.attr('title');
if (title !== 'No alarms') {
var allInnerHtml = '';
for (var i = 1; i < columns.length; i++) {
allInnerHtml += $(columns[i]).find('div').html() + '\n';
}
alert(allInnerHtml);
}
else {
//just to show that titles with 'No alarm' are skipped
alert('skipped');
}
});
});
See updated JSFiddle
Hope that helps! =)
If your Div tree has classes in the same format is now you can use something like this.
var title = $('.x-panel-bwrap').find('img').attr('title');
Or if the div class dependency is not confirmed, then assuming that img tag will always have a class name starting with 'tick', you can use this.
var title = $('img *[class^="tick"]').attr('title');
EDIT
Now that you have explained your problem more clearly, i've included a fiddle with the solution you need. Now you will have to expand it to suit your code more closely.
For example if you want to log each location separately, start looping through the locations first and then find tables inside them.
Basically you can use Jquery .find and .each to go through your comeplete html and do whetever you want.
var tableList = $('.x-grid3-row-table');
tableList.each(function() {
var imgTitle = $(this).find('img').attr('title');
alert(imgTitle);
if (imgTitle == 'Warning') {
infoTd = $(this).find('td:nth-child(3)');
text = infoTd.find('div').text();
alert(text);
}
});
FIDDLE

Categories