.find is not a function on cheerio object - javascript

let playersCell = `
<td class="foo" colspan="2">
<a href="example.com">
<span class="bold">John Beluga</span>
- Sarah Jay.
</a>
</td>
`
let players = cheerio.load(playersCell)
players.find('a').html()
I try to load a html string into cheerio.js and find an a tag, but I am getting
[TypeError: players.find is not a function]
Console.log shows for players

I got .find is not a function, and when I looked at the object in the console that I was trying to find, it said its type was tag. I realized I needed to wrap the object again.
let results = $('.your .query')
results.each((i, r) => {
$(r).find('.your .next .query')
})

find is a method that appears on DOM search results. You need to create a result before you can use find.
For example:
let playersCell = `<table><tr>
<td class="foo" colspan="2">
<a href="example.com">
<span class="bold">John Beluga</span>
- Sarah Jay.
</a>
</td></tr></table>
`
let players = cheerio.load(playersCell);
console.log(players('td').find('a').html());
<script src="https://wzrd.in/standalone/cheerio#latest"></script>
But in this case, there is no need to. You can just use the initial search directly:
let playersCell = `
<td class="foo" colspan="2">
<a href="example.com">
<span class="bold">John Beluga</span>
- Sarah Jay.
</a>
</td>
`
let players = cheerio.load(playersCell);
console.log(players('a').html());
<script src="https://wzrd.in/standalone/cheerio#latest"></script>

Related

How to prevent replacing HTML elements when using innerHTML?

I'm matching HTML elements based on their textContent. Then surronding that match with <strong> tags:
const element = [...document.querySelectorAll('a')]
.find(element => element.textContent.match('b'))
element.innerHTML = element.innerHTML.replace('b', '<strong>$&</strong>')
<a href="#">
<br>
<h3>blog</h3>
</a>
There's a problem, though. The code also matches HTML elements. So I get this:
<a href="#">
<<strong>b</strong>r>
<h3>blog</h3>
</a>
Instead of the desired result:
<a href="#">
<br>
<h3>blog</h3>
</a>
How to change my code so it doesn't match HTML elements? Only the text inside them?
Iterate over the children elements of your anchors and reset the HTML based on whether the textContent of the element contains "b".
Note: find will only find the first instance of the thing you're looking for. You need to explicitly iterate over all of the things.
The find() method returns the value of the first element in the provided array that satisfies the provided testing function. If no values satisfy the testing function, undefined is returned.
const elements = [...document.querySelectorAll('a')];
function embolden(elements, str) {
elements.forEach(element => {
[...element.children].forEach(child => {
if (child.textContent.includes('b')) {
child.innerHTML = child.textContent.replace('b', '<strong>b</strong>');
}
});
});
}
embolden(elements, 'b');
<a href="#">
<br>
<p>blog</p>
</a>
<a href="#">
<br>
<p>blog</p>
<p>Peterborough</p>
</a>
Use innerText instead of innerHTML to match. Insert the replaced values in the innerHTML
const element = [...document.querySelectorAll('#example')]
.find(element => element.textContent.match('b'))
element.innerHTML = element.innerText.replace('b', '<strong>$&</strong>')
<div id="example">
<div>This is some text.</div>
<br>
<div> This is part of the body </div>
</div>
You can use this regex: /(?!<[^>]+)b(?![^<]+>)/g
const element = [...document.querySelectorAll('a')]
.find(element => element.textContent.match('b'))
const string = "b";
const reg = new RegExp("(?!<[^>]+)" + string + "(?![^<]+>)", "g");
element.innerHTML = element.innerHTML.replace(reg, '<mark>$&</mark>')
mark
{
background-color: lightgreen;
}
<a href="#">
<br>
<h3 title="attributes are not affected bbbb">blog hover blog</h3>
</a>

How to scraping there are not class using javascript

How to scrap data when there are not any class I know way using ID,Class using document.getElementsByClassName.
<tr id="overview-summary-current">
<th scope="row">
<span class="edit-tools">
<a href="#background-experience" class="edit-section" id="control_gen_5">Edit experience
</a>
</span>
Current
</th>
<td>
<ol>
<li>
<strong>
SNT Solutions rajkot
</strong>
</li>
</ol>
</td>
</tr>
I want SNT Solutions rajkot how to get that value in variable using JavaScript.
trk=prof-0-ovw-curr_pos is unique in webpage
Simple way(pure js):
var linksWithoutClass = document.querySelectorAll('#overview-summary-current a'); // return nodeList iterrator
var linksArray = [].slice.call(linksWithoutClass); // create array from Nodelist
linksArray.filter( function(link){ // filter list to get <a> without any class
return link.classList.length === 0;
});
I got simple solution for that
var a1 = document.querySelector('a[href$="trk=prof-0-ovw-curr_pos"]').text;
console.log('Data is :::::'+a1);

how to bind data from dynamically named inputs inside a ng-repeat

my goal is to be able to copy data from a table row to another table row.
if the data from 2015 has not changed from 2016 the user needs a quick way of copying the values into the 2016 input fields. the models are dynamically created for these forms. the data you see in this image is assigned to a section. the input models are name 'price_min + section_id', price_max + section_id' , etc...
the history model does not have the section_id added to the end of the model names. so there needs to be a mapping function that i need help with. I need to map the history values to the current model convention and update the view with the values.
currently i have a click function that brings in the matched section history. here is a screen shot of what that looks like.
in that same function i have the 2016 object array with the current model naming convention.
i need to copy the history values into the inputArray. how i go about doing this, i dont know? I have complete control on how this works. and in the plunker you will see how i did this. if i need to change something else to make this work then that is ok. javascript, jquery, lodash, linq.js is currently being used in project.
working plunker
working plunker
$scope.copyHistoryData = function (section) {
var selected = Enumerable.From(sectionsHistory).Where("x => x.section_id == '" + section.section_id + "'").ToArray();
selected = selected[0];
var inputArry = section.sectionInputs;
};
I'm not sure why you use such complex data structure, but here is my take on it
$scope.copyHistoryData = function (section, input) {
var historyId=input.model.split('-')[0];
var historyVal=section.sectionHistory[section.sectionHistory.length-1][historyId];
$scope.model[input.model]=historyVal;
};
To fill all fields:
$scope.copyHistoryData = function (section) {
angular.forEach(section.sectionHistory[section.sectionHistory.length-1], function (historyVal, historyId) {
var inputModel=historyId+"-"+section.section_id;
$scope.model[inputModel]=historyVal;
});
};
http://plnkr.co/edit/OOEmgzKB1pqKjSJMayVF?p=preview
I agree with #ssh. The data structure is a mess. I think this is a better representation of what it should look like. Probably not the best but you shouldn't have to iterate through the data to then display it like that.
http://plnkr.co/C9DWV1dSvkk8lcYdm0An?p=preview
<div class="hpanel" ng-repeat="section in sections">
<div class="panel-body">
<div class="row">
<div class="col-xs-12">
<ul class="list-inline">
<li>
<h5>
<b>SecID</b>
</h5>
<span>{{section.section_id}}</span>
</li>
<li>
<h5>
<b>Section Name</b>
</h5>
<span>{{section.section_name}}</span>
</li>
</ul>
<hr/>
<button ng-click="section.new_section_history = section.section_history">copy row</button>
<table>
<tr>
<td ng-repeat="label in labelIndex">
{{label.label}}
</td>
</tr>
<tr>
<td ng-repeat="label in labelIndex">
{{section.section_history[label.index]}}
</td>
</tr>
<tr>
<td ng-repeat="label in labelIndex">
<input ng-model="section.new_section_history[label.index]"/>
</td>
</tr>
<tr>
<td ng-repeat="label in labelIndex">
<button ng-click="section.new_section_history[label.index] = section.section_history[label.index]">copy</button>
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
I have checked your code, and I agree with #Steven Kaspar, the anchors in every row doesn't make much sense. I have solved it using jQuery (I know it doesn't follow your scheme with Angular, but it's another solution).
I have added a new <tr> to add a button inside it.
Check this out:
<tr>
<td colspan="10"><button class="copyRow">Copy complete row</button></td>
</tr>
And in the app.js:
$(document).on("click", ".copyRow", function(){
var $btn = $(this),
$tbody = $btn.parent().parent().parent(),
$trs = $tbody.find("tr");
$.each($trs.eq(0).find("td"), function(index, td){
$trs.eq(1).find("td").eq(index).find("input").val(parseFloat($(td).text().replace("$", "")));
});
})
Here is the updated plunker. I hope it helps

javascript function with document.querySelectorAll plus filter() can't work properly

I want to get rid of those <tr> with <span class="verfied-badge"> inside it using javascript. (please note that I am hoping for a solution that is javascript only, no jquery)
The HTML structure is like this:
<tr class="project-description">
<td colspan="6">
<div class="project-desc-inner">
<div class="project-synopsis">
<p class="trunk8">This is an entry</p>
</div>
<div class="project-verification">
<span class="verfied-badge"> <~~~~~~~~~~ THIS SPAN
<span class="currency-symbol">$</span>
<span class="icon-tick"></span>
Verified
</span>
</div>
<div class="project-actions">
<a href="#">
<button class="btn">LOL</button>
</a>
</div>
</div>
</td>
</tr>
And this is as far as I can come up to:
function showAlert()
{
document.querySelectorAll("tr.project-description").filter(document.getElementsByClassName("verfied-badge")).remove();
alert("Unwanted removed.");
}
What I hope it does is, select all tr.project-description then from those get all with have span.verfied-badge and if it does have it, delete the entire tr
but as it seems, I keep failing :(
Hope somebody can help.
Thanks!
Find all the tr elements you care about, then see if they containing a matched verified-badge span. If they do, burninate remove them.
window.addEventListener('load', function() {
var projectDescriptions = document.querySelectorAll('tr.project-description'),
projectDescriptions = Array.prototype.slice.call(projectDescriptions);
projectDescriptions.forEach(function(el) {
if (el.querySelector('span.verfied-badge')) {
el.parentNode.removeChild(el);
}
});
});
I called Array.prototype.slice on the NodeList returned from querySelectorAll because querySelectorAll doesn't return an array but a NodeList, which is one of JavaScript's irritating (but easy to workaround) "Array-like objects".

delete the current <tr> and also delete the <tr> before it using plain javascript

I have this HTML structure:
<tr class="project-details">REMOVE THIS</tr>
<tr class="project-description">
<td colspan="6">
<div class="project-desc-inner">
<div class="project-synopsis">
<p class="trunk8">This is an entry</p>
</div>
<div class="project-verification">
<span class="verfied-badge"> <~~~~~~~~~~ THIS SPAN
<span class="currency-symbol">$</span>
<span class="icon-tick"></span>
Verified
</span>
</div>
<div class="project-actions">
<a href="#">
<button class="btn">LOL</button>
</a>
</div>
</div>
</td>
</tr>
And I hope that the entire <tr class="project-details">REMOVE THIS</tr> plus its contents will be remove completely
This is what I have so far:
function showAlert()
{
var projectDescriptions = document.querySelectorAll('tr.project-description'),
projectDescriptions = Array.prototype.slice.call(projectDescriptions);
projectDescriptions.forEach(function(el) {
if (el.querySelector('span.verfied-badge')) {
}else {
el.parentNode.removeChild(el);
el.prev('tr').remove();
}
});
}
What it does is select the <tr> with the <span> I am looking for, then delete the entire span. This part el.prev('tr').remove(); is not working, any alternative?
Thanks!
The body of the else clause:
(function removePreviousSibling(sibling) {
if (sibling.nodeName === 'TR' && sibling.classList.contains('project-details')) {
return sibling.parentNode.removeChild(sibling);
}
removePreviousSibling(sibling.previousSibling);
}(el.previousSibling));
el.parentNode.removeChild(el);
The IIFE ensures if there is an extra text node between the two <tr> elements that the text node will be skipped and not deleted if you just did called a removeChild on the previousSibling of the target element.
Take a look over the information at MDN's DOM page. It's got a great set of interface documentation and tutorials.
prev is a method of a jQuery object. HTMLElement object has no prev method. For selecting the previous element sibling you can use the previousElementSibling property.

Categories

Resources