Could someone look at the following screenshot for me and explain the following:
What is going on?
How can I programmatically detect it?
How can I programmatically fix / get rid of it?
I believe what's happening is I have multiple text nodes in a single pre element... I feel like I read on MDN many years ago that such a thing is possible, but I've never encountered anything like it before now.
jQuery doesn't reveal anything unusual about it via text() or html() (I attempt both in the console as seen in the screenshot)... it simply shows the content of all the text nodes consolidated into a single node.
Not shown is that when I attempt to manually fix this in the console, by doing:
$('pre').text($('pre').text())
Instead of replacing all the text nodes with a single text node with the content of all 3 merged into one, it only replaces the content of the first text node with the content of all 3.
All of this is really confusing me and I can't find any documentation on any of this, so I'd really appreciate it if someone could answer my questions above.
Oh, because I know someone will ask how I did this, the answer is I'm not quite sure what I did. It has something to do with the circular loop between the html and the js of my meteor project, I think:
In my html I have this:
<pre class="editable" contentEditable="true">{{text}}</pre>
And in my javascript I have this:
"input pre": function (event) {
var newText = $(event.target).text();
Ideas.update(this._id, {$set: {text: newText}});
}
So meteor is automatically checking for changes to text in my database and putting the latest copy into my pre. It also sees when the user edits the pre and edits the text in the database. Something about doing this somehow, sometimes yields what you see in the picture above (other times it yields other strange behaviors.)
What is going on?
There are multiple text nodes in the pre element.
How can I programmatically detect it?
$('pre').contents() will return a list of children of the element, including text nodes. In my case, I'll only ever have text nodes so simply checking if the list has a length greater than 1 will work. If I weren't able to make that assumption, I would have to iterate over the returned list and see if any two consecutive nodes were text nodes. See the documentation from jQuery.
How can I programmatically fix / get rid of it?
$('pre')[0].normalize() fixes it. See the documentation on normalize from MDN.
Related
Code:
const elements = $(".container .element").first().nextAll().addBack();
Here's my HTML:
The code is supposed to grab the first element and all the content after it. Depending on the HTML, this could return at a lot of different things, including nothing if I have a typo in my jQuery code. If the code that follows doesn't function correctly, how do I see what's inside elements for troubleshooting purposes?
I tried logging elements.html(), but that only printed the contents of the first element.
I tried using the Firefox debugger on elements, but the object is very complex, contains a lot of irrelevant troubleshooting information, and I couldn't figure out how to find what the jQuery object actually represents.
The only way I could figure out my code was correct was by logging elements.text(). That printed the text inside every element, and by doing that, I knew I had grabbed each one. It didn't tell me I grabbed the BR tags, but the documentation for nextAll said it would, so the gave me another faith it was doing what I wanted (I don't like relying on faith). The other problem with this solution is that it's highly contextual and won't work in all situations. There won't always be text in the HTML.
I'm out of ideas. How do I see what's inside a jQuery object for troubleshooting purposes?
Use
console.log(elements.get())
The jQuery get() method with no arguments returns the contained DOM elements as an array.
I'm relatively new to using Chrome developer tools/doing XPath searches/this kind of programming in general, so please excuse any incorrect terminology or vague-sounding descriptions. I think the screenshots below will demonstrate what I'm talking about more easily than I can describe with my limited vocabulary.
What I'm Looking For
When I started using developer tools to search XPaths, using the "$x(...)" function would return a section of the html, that I could then navigate within the console or with more specific searches to get a sense of the structure before I extracted text. My console is no longer returning the markup text in this form, but I found an example in another StackOverflow post that will suffice to show what kind of return I'm looking for:
What I would be looking for
I was able to navigate this HTML text within the console (highlighted section) to find the section I needed, before using a more specific XPath, extracting, etc.
What I'm Seeing Now
What I'm now getting instead is an array or nested set of arrays. I think that these are jQuery objects being returned (could be way off here). See below:
What I'm seeing now
I'm sure that in many cases, navigating the elements in this array could actually be easier than working through the HTML and, as someone with very little exposure to web development, I'm sure that there's something I'm missing here. As someone working on a scraping project just looking to find specific elements or text on the page. This is much more difficult to work with.
As a made up example, in the past, if I were trying to pull the names of different kinds of fruit off of a page and I typed into the console...
$x('//*[#class="fruit"]/h1')
...the console would have spit out something like:
[<h1>Peach</h1>, <h1>Strawberry</h1>, <h1>Watermelon</h1>, <h1>Apple</h1>, <h1>Orange</h1>]
And then, had I followed that up with...
$x('//*[#class="fruit"]/h1.text()')
...the console would have spit out:
["Peach", "Strawberry", "Watermelon", "Apple", "Orange"]
Now, if I run a search like this, I'll get a result that will (not literally, but in this form) look something like this:
Array[2]0: form#aspnetForm0: input#__LASTFOCUS1: input#__EVENTTARGET2: input#__EVENTARGUMENT3: input#EktronClientManager4: input#__VIEWSTATE5: input#__VIEWSTATEGENERATOR6: input#__EVENTVALIDATION7: input#ctl00_Header_searchTextBox.searchterm8: input#ctl00_Header_searchButton.searchbtn9: fieldset10: input#ctl00_contentPlaceHolder_login_emailTextBox.max-width11: input#ctl00_contentPlaceHolder_login_passwordTextBox.max-width12: input#ctl00_contentPlaceHolder_login_rememberMeCheckBox13: input#ctl00_contentPlaceHolder_login_signInButton.button.green_events: etc, etc...
For my purposes, that array of strings is much easier to work with, because I can confirm exactly what I'm getting from that XPath search and what I'm going to have to work with once I get the element off the site.
I'm sorry that this post is probably really frustrating to an experienced web programmer, because I'm missing both the larger picture and a lot of the vocabulary. Could someone please explain to me 1. what I going on? Why am I getting these arrays full of data when I was getting the HTML text before and 2. how to revert to getting the HTML text returned when I do this kind of search in the JavaScript console?
Thank you!
There is no difference between the "what I would be looking for" and "what I'm seeing now" screenshots. When you click on the little triangle to the left of "what I would be looking for", you can see that it becomes equivalent to the "what I'm seeing now" format.
For example, opening up DevTools on this very Stack Overflow page, and searching for <h2> elements:
When you click on the little triangle to the left of the result you get:
The $x() function returns a JavaScript array (not jQuery) of DOM nodes that match your XPath query. If there's multiple nodes that match your query, then the result will be an array of multiple nodes.
You can iterate through the results by assigning the results to an array, and then looping through them, like in the screenshot below. I think this is the kind of functionality that you're looking for.
I'm trying to scrape data from this Chinese webpage http://bxt.harbin.gov.cn/hrb_bzbxt/disshow.php?id=551950.
In Scrapy shell, I cannot get any text in any td elements. For example, response.xpath("/html/body/center[2]/table/tbody/tr[2]/td[3]/text()").extract() returns an empty list. The same thing is returned for other similar commands too. When I inspect the html more closely, I find this in the head element: "script language = "javascript". I'm not sure if this is the cause of the problem. Could anybody help me figure out? I searched Stackoverflow for related topics, but it's too complex for me to grasp. Thank you for your help!
the problem here is that you are using a full path to get to the information you want, this isn't necessary, so no need to follow html -> body -> center, etc.
You could just go directly to the td information you need, with something like:
response.xpath('//td/text()')
which will return a list of selectors (every text inside a td tag) to iterate with the information you need.
Hi I've searched and found different things based loosely around this and some more closely tied but I haven't been able to devise and create a workable solution for the problem I'm having:
Summary:
I am looking to create a view in a specific way due to my requirements. This is currently looking at using a self implemented Treeview style - I don't wish to use any kind of other plugins or pre-made views at the moment, because as you can see by the attached JS fiddle demo at the bottom, I can achieve this myself.
Problem At Hand:
This may be stupidly easy or straightforward and if so please forgive my incompetence but the problem is coming down to the tags - which have text in-between like so:
<ul><checkbox class="collapsible" /><label>Value 1</label>...<ul>
now I have no problem retrieving this values - as there is quite a few in the list of them (one for each option). But finally the base of the problem is matching these to my search input. While I have used the very obvious and generic for each loop it has a problem actually matching the 'input' - my variable for the search input - and the label's text together - hence it wont alert the correct values and can sometimes alert all 15 values when only 4 may match...
Any help would be greatly appreciated with this - feel free to use any of the tree view code which works very nicely alongside the select boxes.
Side note
In my actual view these check boxes will be associated with the label names using an object class to populate the value. Also I want, not really alert the matching labels, but to highlight them - so if anyone could help with that or suggest anything as well that would be nice - not the critical problem though. (sorry i know this is no help or use to you but I thought id enlighten you as to my reasons for alerting these labels.)
MY JS FIDDLE DEMO - TREEVIEW -- EDIT: this was the answer I needed (i will leave it here incase anyone else wants to use this), answer perfectly supplied by Radu Andrei
EDIT: I am not looking to alert based on any criteria asides the fact that the labels text matches the search text.
Answer to the question can be found in the fiddle -> https://jsfiddle.net/mLbhLh89/11/ .
Try as shown in the fiddle
FIDDLE
I just updated your search function with following
$("#search").on("click", function() {
$("label").each(function(i,v){
if($(this).text().indexOf($("#search-criteria").val())>0){
alert($(this).text());
}
});
});
It will find the search string in each label text and show an alert if found.
I would like to a keep an text became non-editable. still it's parent as editable mode. it's not working with ie9 i have posted a question regarding here. But yet to get the suggestion.
`ie9` - contenteditable false not working when parent editable
But mean while, I searched and find a information says that,
Any element with the "mceNonEditable" class will be blocked from modifications and treated as a single character.
at here: http://www.tinymce.com/wiki.php/Plugin:noneditable
But I am not in the position to use this plugin-now. since i have 600 pages+ with numerous instance need to replace. the site in UAT status.
Considering all, i looking for a solution, using jQuery to convert a class based element into single letter as like noted above.
Is it possible? if so any one have an idea to share?
Please help me.