List items from HTML XPath - javascript

I need to list items returned from evaluating an Xpath. I'd like to return the tweets in a list, so I can further evaluate their elements. How do I do this?
My code is:
var navigable_stream = '//*[#id="stream-items-id"]';
var FIRST_RECORD = document.evaluate(navigable_stream, document, null, XPathResult.ANY_TYPE, null).iterateNext();
console.log(FIRST_RECORD);
And the returned HTML is very long. But it has lots of tweets with different ids. Here's a picture to show what I mean:

Update
" Is there a way to match the first part of the element id i.e. 'stream-item-tweet"?"
Yes, by using referencing the partial #id as an attribute:
var tweet = document.querySelectorAll("[id^=stream-item-tweet]");
Note the ^= means that the beginning of the #id must match stream-item-tweet
Having answered the question I'd like to add that there may be a better alternative by using the class of each <li>:
var tweet = document.querySelectorAll('.js-stream-item')
Something looks invalid on the classList:
class="js-stream-item stream-item stream-item"
.stream-item is repeated twice...maybe it's best to avoid class in your circumstance.
Anyways, knowing the first way should work and maybe the second way might, tweet is now a NodeList which needs to be handled by a loop or it needs to be converted to an array so it can be processed by an array method.
Demo 2 shows how the latter is done.
Just guessing, since there's no way I can test it myself, that if that's what you can get on the console, then you could maybe use .toString() then parse and append it to the DOM.
Demo 1
Not possible to make an actual functioning Demo
var navigable_stream = '//*[#id="stream-items-id"]';
var FIRST_RECORD = document.evaluate(navigable_stream, document, null, XPathResult.ANY_TYPE, null).iterateNext();
console.log(FIRST_RECORD);
var str = FIRST_RECORD.toString();
document.getElementById('dock01').insertAdjacentHTML('beforeend', str);
<section id='dock01'></section>
Demo 2
/* Collect all elements with an #id that starts with "tweet"
|| Convert NodeList into an array
*/
var tweets = Array.from(document.querySelectorAll("[id^=tweet]"));
/* filter() the array tweets
|| if an item has data-id = "retweet"
|| add it to the new array retweets
*/
var retweets = tweets.filter(function(t) {
return t.dataset.id === "retweet";
});
console.log(retweets);
/* The lazy way to add text */
li::after {
content: attr(id);
}
/* This is just so the console results don't obscure the Demo*/
.as-console-wrapper {
width: 70%;
margin-left: 30%;
}
.as-console-row:after {
display: none !important;
}
<ol>
<li id='tweet-51515151' data-id='retweet'></li>
<li id='tweet-57885157' data-id='tweet'></li>
<li id='tweet-51677459' data-id='tweet'></li>
<li id='tweet-51890331' data-id='retweet'></li>
<li id='tweet-51515337' data-id='retweet'></li>
<li id='tweet-51593051' data-id='retweet'></li>
<li id='tweet-51333333' data-id='tweet'></li>
<li id='tweet-51534152' data-id='tweet'></li>
<li id='tweet-51599951' data-id='tweet'></li>
<li id='tweet-54785151' data-id='retweet'></li>
<li id='tweet-56785199' data-id='retweet'></li>
<li id='tweet-51557844' data-id='tweet'></li>
<li id='tweet-51510000' data-id='retweet'></li>
</ol>

Related

Get href list under HTML content

I have a json string which contains HTML element. What I am trying to achieve is to fetch all anchor tag value <a> in that string.
Json String
"content" : "<p>Reference information</p> <ul> <li>My Url</li> <li>Your Url</li> </ul>"
Here is HTML Format
<p>Reference information</p>
<ul>
<li>My Url</li>
<li>Your Url</li>
</ul>
I have tried like this but cannot get exact value:
<div id="TestDiv" hidden >
</div>
let anchor = document.getElementById("TestDiv").getElementsByTagName("li");
anchor[0].innerHTML
I am getting this value
My Url
But I want to get https://myurl.com
another way I tried which was closed though still has problem but don't want to use regex:
content.match(/href="([^"]*?)"/);
How can I achieve that?
// Create an element
const el = document.createElement("div");
// set the inner HTML
el.innerHTML = `
<p>Reference information</p>
<ul>
<li>My Url</li>
<li>Your Url</li>
</ul>
`;
// grab all <a> tag
const nodeList = el.querySelectorAll("a");
// convert to array
const nodeArray = [...nodeList];
// map to href
const hrefs = nodeArray.map((a) => a.href); // ["https://myurl.com/", "https://yoururl.com/"]
You can use Array.prototype.map like:
var anchorUrls = Array.prototype.map.call(
document.anchors, (i) => i.href;
);
console.log(anchorUrls);
You can access the href attribute value using .href or using the getAttribute("href") method. However you are currently getting the li elements, but you want to instead get the anchor elements.
let anchor = document.getElementById("TestDiv").getElementsByTagName("a");
anchor[0].href;
To get all of the href's you will need to loop through the array of anchors.
var i;
for (i = 0; i < anchor.length; i++) {
anchor[i].href;
}

CSS exclude cascade classes

Web Mind Help! I have html with many lists looks like
<li>A.</li>
<li>B.</li>
<li><a class=tr href="#">C.</a></li>
<li class=tr>D.</li>
<li class=notr>E.</li>
I want select all untranslated innerText
document.querySelectorAll("li:not(.notr):not(.tr)")
Problem is if class TR not in LI i cannot filter it
li:not(.notr):not(.tr)+li>a:not(.tr) - returns empty NodeList
It seems to be a simple question but I'm confused
Like I said in the comments, the solution is to fetch this collection first, then refine the results by running another filter over that.
let rawresult = document.querySelectorAll("li:not(.notr):not(.tr)");
console.log('raw results:');
rawresult.forEach(el => console.log(el.innerText));
let refinedresult = [];
rawresult.forEach(function(el) {if (el.querySelector(".notr,.tr") == null) refinedresult.push(el);});
console.log('refined results:');
refinedresult.forEach(el => console.log(el.innerText));
<ul>
<li>A.</li>
<li>B.</li>
<li><a class=tr href="#">C.</a></li>
<li class=tr>D.</li>
<li class=notr>E.</li>
</ul>

How to change the id of a unordered list of object type in jQuery object

I'm new here and I'd like to ask a question about jQuery.
I have the unordered list like:
<ul id="pages">
<li id="number1">
contains sub table a
</li>
<li id="number2">
contains sub table b
</li>
<li id="number3">
contains sub table c
</li>
<li id="number4">
contains sub table d
</li>
</ul>
And I'd like to add a different ID (new id will be same out of these id but it will be shuffle as per my requirements) to every li displayed in this <ul> (eg
<li id="number3">contains sub table d</li>
...)
Is there a way how to achieve this via jQuery?
I tried it using a for loop and this object but when i try to shuffle. Its duplicating the sub tables becouse of jQuery has child/nextsybling data inside this every object.
Basically you should get all ids, shuffle them and reassign back to DOM elements:
const $items = $('#pages li');
const ids = $items.map((i, { id }) => id);
const shuffledIds = shuffle(ids); // This is your shuffle function
$items.each((i, e) => {
e.id = shuffledIds[i];
});

Filter the list with letter in angular js

I have a list displayed in table where I need to filter the result with first letter of name,above the list I have a letter A B C D and so on.
After click the letter list will be filter by its first name
For ex: list details are Apple Boy Bridge
after click A, Apple will be displayed
Instead of fruit, I had to filter names of countries to display their sales representatives:
'use strict';
angular.module('sodemo')
.filter('firstLetter', function () {
return function (input, letter) {
input = input || [];
var out = [];
input.forEach(function (item) {
//console.log("current item is", item, item.charAt(0));
if (item.charAt(0).toLowerCase() == letter) {
out.push(item);
}
});
return out;
}
});
A quick way to generate an array with letters of the alphabet:
$scope.alphabet = "abcdefghijklmnopqrstuvwxyz".split("");
and the view, which also sets a different background colour if the letter is active:
<button type="button" class="btn-alphabet btn btn-default" ng-repeat="letter in alphabet" ng-click="setActiveLetter(letter)" ng-class="{'btn-primary': letter==activeLetter}">{{letter}}</button>
I filtered elements of the array of countries like this:
<ul class="list-group countries-salesreps" >
<li class="list-group-item" ng-repeat="country in filteredCountriesArray = (countriesArray | firstLetter:activeLetter)" ng-click="showSalesRep(country)" ng-class="{'btn-primary': country==currentCountry}">{{country}}</li>
</ul>
You can check if there are elements in the filtered list using .length:
<div class="alert alert-warning" ng-hide="filteredCountriesArray.length">No available countries starting with <em>{{activeLetter}}</em></div>
So the question has been answered but I came across this looking for an answer and being quite new to angular found it kind of hard to read and understand properly. I then found this tutorial explaining filters and how they work in general and in his examples he creates a 'startsWithLetter' filter which I found quite useful: http://toddmotto.com/everything-about-custom-filters-in-angular-js/
Just thought I would post it in case anyone had trouble understanding like I did.
this is old but maybe this plunker can help, using angular's filter filter.
Define an expression like so:
// Filter Expression
this.filterActive = function(value){
if (self.active) {
return value.charAt(0).toLowerCase() === self.active;
}
return true;
}
Then in html:
<ul>
<li ng-repeat="country in ctrl.countries | filter:ctrl.filterActive" ng-bind="country"></li>
</ul>
<ul>
<li>A</li>
<li>B</li>
<li>C</li>
</ul>
<ul>
<li ng-repeat="name in list | filter:letterFilter">
{{name.firstName}}
</li>
</ul>
try above code this is simple to implement:

jQuery cloned list items all get the same text values while using each() function

I am trying to clone a list item in the DOM and append it multiple times depending on the number of text values in the variable data using the each function. The problem is that all the new list items get the same text values (all list items are set equal to the last appended list item).
I suppose it has something to do with enclosures, but I cannot figure it out.
Can anyone explain what the problem is?
Thanks!
data:
var data = {"text1": ["text1_row1", "text1_row2"], "text2": ["text2_row1", "text2_row2"], "text3": ["text3_row1", "text3_row2"] }
HTML:
<ul>
<li id="entryTemplate" style="display:none">
<span class="text1"></span>
<span class="text2"></span>
<span class="text3"></span>
</li>
</ul>
Javascript:
function listData(data){
$.each(data.text1, function(i) {
var newDataRow = $('#entryTemplate').clone();
newDataRow.removeAttr('id')
.removeAttr('style')
.removeAttr('class')
.addClass('copy')
.appendTo('ul')
.find('.text1').text(data.text1[i])
.find('.text2').text(data.text2[i])
.find('.text3').text(data.text3[i]);
});
}
$.fn.clone = function(){
var ret = $();
this.each(function(){
ret.push(this.cloneNode(true))
});
return ret;
};
Desired HTML:
<ul>
<li id="entryTemplate" style="display:none">
<span class="text1"></span>
<span class="text2"></span>
<span class="text3"></span>
</li>
<li class="copy">
<span class="text1">text1_row1</span>
<span class="text2">text2_row1</span>
<span class="text3">text3_row1</span>
</li>
<li class="copy">
<span class="text1">text1_row2</span>
<span class="text2">text2_row2</span>
<span class="text3">text3_row2</span>
</li>
</ul>
Result I get (all li items get the text for row2):
<ul>
<li id="entryTemplate" style="display:none">
<span class="text1"></span>
<span class="text2"></span>
<span class="text3"></span>
</li>
<li class="copy">
<span class="text1">text1_row2</span>
<span class="text2">text2_row2</span>
<span class="text3">text3_row2</span>
</li>
<li class="copy">
<span class="text1">text1_row2</span>
<span class="text2">text2_row2</span>
<span class="text3">text3_row2</span>
</li>
</ul>
Your question is a bit foggy and it's not really clear what's the result you're looking for. Appart from that I saw something in your code that's probably causing it. Give it a try and let me know what happened.
When you do
$.each(data.text1, function(i) {
change it to
$.each(data.text1, function(pos, element) {
and replace your [ i ] for [element].
According to JQuery API, when doing an EACH loop, the 1st return is the position in the array and the second is the value itself.
UPDATED ANSWER:
Your data object variable is formatted wrong... It looks like you want each value of the data object to be an array (using curly brackets implies you are defining an object with keys), so you should be using square brackets []. See array vs array-like object
var data = {
"text1": ["text1_row1", "text1_row2"],
"text2": ["text2_row1", "text2_row2"],
"text3": ["text3_row1", "text3_row2"]
}
jQuery already has a clone method so you shouldn't need to override with your own.
Based on the data you provided, you want to be iterating over the data variable itself, not data.text1. Then you can get the text values by value of the current index (this is the second parameter passed to .each()) and referencing [0] and [1] to get the actual text
$.each(data,function(i,value){
console.log(value);
var newDataRow = $("#entryTemplate").clone();
newDataRow
.removeAttr('id')
.removeAttr('style')
.removeAttr('class')
.addClass('copy')
.appendTo('ul');
newDataRow.children('.text1').text(value[0]); // value[0] == data[i][0]
newDataRow.children('.text2').text(value[1]);
});

Categories