split string of spans into array of spans - html

I have a block of text wrapped in spans that I need to split into an array.
So currently I have
var s = `
<span class="hoverable">c</span>
<span class="hoverable">o</span>
<span class="not-hoverable">o</span>`;
I need
var s = [
"<span class="hoverable">c</span>",
"<span class="hoverable">o</span>",
"<span class="not-hoverable">o</span>"];
I've tried s.split(/<\/?span>/); to split accounting for <span> and closing </span> but
var s = [
"<span class="hoverable">c",
"<span class="hoverable">o",
"<span class="not-hoverable">o",...]
So it's not including the closing span.

As always when a regexp question wanders over into HTML or XML territory, I suggest regexp is not the right tool. Use the proper HTML parser available in the language you are using. In case of JavaScript (implied by your use of var and string template syntax):
let s = `
<span class="hoverable">c</span>
<span class="hoverable">o</span>
<span class="not-hoverable">o</span>`;
let d = document.createElement('div');
d.innerHTML = s;
let result = Array.from(d.children).map(e => e.outerHTML);
console.log(result);

You can always use the DOM if you are working in a browser and the value is inside of an element. If it is not and you have a string then you can still use DOM dynamically. Finally, you can use regular expressions.
Here's a round up:
var s = ' ' +
'<span class="hoverable">c</span>' +
'<span class="hoverable">o</span>' +
'<span class="not-hoverable">o</span> ';
var r2 = s.match(/<span(.*?)>(.*?)<\/span>/gm);
console.log("using regular expressions");
console.log(r2);
function findWithDOM() {
console.log("using DOM");
var elements = [].slice.call(document.querySelectorAll('#myDiv span'));
console.log(elements);
}
function findWithDynamicDOM() {
console.log("using Dynamic DOM");
var element = document.createElement("div");
element.innerHTML=s;
var elements = [].slice.call(element.querySelectorAll('span'));
console.log(elements);
}
<div id="myDiv"><span class="hoverable">c</span>
<span class="hoverable">o</span>
<span class="not-hoverable">o</span>
</div>
<input id='btnFind' onclick='findWithDOM()' value='Find With DOM' type="button" />
<input id='btnFind' onclick='findWithDynamicDOM()' value='Find Dynamic DOM' type="button" />

Related

How to hide some text in string using CSS

Please find updated code
<html>
<title>css</title>
<head>
<style>
#st {
z-index: -114;
margin-right: -80px;
}
</style>
</head>
State Code : <span><span id="st"></span>Maharashtra - MH</span>
</html>
I got below output but i need clear overlapped text
enter image description here
the only way to approach this is using css display: none or visibility: hidden property , either one would work, i would advice display none. this is the only way CSS and HTML can hide data.
<span>State Code: <span id="st"><span style="display: none">Maharashtra - </span>MH</span></span>
You Can't do this by using CSS only here is the javascript solution for u
$("#st").html(function(){
var text= $(this).text().trim().split(" ");
var first = text.shift();
return (text.length > 0 ? "<span class='hide'>"+ first + "</span> " : first) + text.join(" ");
});
.hide {
display:none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span>State Code: <span id="st">Maharashtra - MH</span></span>
see this is HTML version but it is working fine.
<span id="span_Id">Maharashtra - MH</span>
<script>
function getSecondPart(str) {
return str.split('-')[1];
}
var span_Text = document.getElementById("span_Id").innerText;
var html = getSecondPart(span_Text);
document.getElementById("span_Id").innerHTML = html;
</script>
Update 2
Layout has significantly changed...see 2nd updated demo.
Since OP has dynamically generated text, JavaScript is needed realistically. And probably the actual text will be more than one on the page.
This demo gathers all <span> nested within a <span> (could've used #id but realistically, it should be a .class). This NodeList is converted into an array.
This array is then map()'ped on each iteration a regex is matched vs. the <span>s text.
A replace()'ment of the unwanted portion of text is overwritten and the last 2 letters remain.
Demo
var tgt = Array.from(document.querySelectorAll('span'));
tgt.map(function(s, idx) {
var str = s.textContent;
var rgx = /(State Code:).*?- (\w\w)/g;
var rep = `$1 $2`;
var res = str.replace(rgx, rep);
s.textContent = res;
});
<span>State Code: <span class="st"></span>California - CA</span><br>
<span>State Code: <span class="st"></span>New York - NY</span><br>
<span>State Code: <span class="st"></span>Oregon - OR</span><br>
<span>State Code: <span class="st"></span>Mississippi - MS</span><br>
If you use PHP... try it below..
$string = explode("-","Maharashtra - MH");
<span>State Code: <span id="st"><span style="display:none;"><?php echo $sting[0]."-"; ?></span><?php echo $string[1]; ?></span></span>

unable to select a table within div using html agility pack

image of div tree
I am trying to scrape data from a table in a web page using htmlagilitypack.
Below is the html portion
<div id="table-matches" style="display: block;"><table class=" table-main"><colgroup><col width="50"><col width="*"><col width="50"><col width="50"><col width="50"><col width="50"><col width="50"></colgroup><tbody><tr class="dark center" xtid="28575"><th class="first2 tl" colspan="3"><a class="bfl" href="/hockey/usa/"><span class="ficon f-200"> </span>USA</a><span class="bflp">»</span>ECHL</th><th>1</th><th>X</th><th>2</th><th xparam="Number of available bookmakers odds~2">B's</th></tr><tr class="odd deactivate" xeid="pn36Jn1f"><td class="table-time datet t1496703900-1-1-0-0 ">04:35</td><td class="name table-participant">South Carolina Stingrays - <span class="bold">Colorado Eagles</span><span class="ico-event-info" onmouseover="toolTip('Colorado Eagles wins series 4-0. 4th leg.', this, event, '4');allowHideTootip(false);delayHideTip(200);return false;" onmouseout="allowHideTootip(true);delayHideTip(200);"> </span></td><td class="center bold table-odds table-score">1:2</td><td class="odds-nowrp" xodd="1.91" xoid="E-2nrdfxv464x0x6av8v">1.91</td><td class="odds-nowrp" xodd="4.74" xoid="E-2nrdfxv498x0x0">4.74</td><td class="odds-nowrp result-ok" xodd="2.79" xoid="E-2nrdfxv464x0x6av90">2.79</td><td class="center info-value">1</td></tr><tr class="dark center" xtid="28308"><th class="first2 tl" colspan="3"><a class="bfl" href="/hockey/usa/"><span class="ficon f-200"> </span>USA</a><span class="bflp">»</span>NHL</th><th>1</th><th>X</th><th>2</th><th xparam="Number of available bookmakers odds~2">B's</th></tr><tr class="odd deactivate" xeid="EyxiHGE4"><td class="table-time datet t1496707200-1-1-0-0 ">05:30</td><td class="name table-participant"><span class="bold">Nashville Predators</span> - Pittsburgh Penguins<span class="ico-event-info" onmouseover="toolTip('Series tied 2-2. 4th leg.', this, event, '4');allowHideTootip(false);delayHideTip(200);return false;" onmouseout="allowHideTootip(true);delayHideTip(200);"> </span></td><td class="center bold table-odds table-score">4:1</td><td class="odds-nowrp result-ok" xodd="2.15" xoid="E-2ns9hxv464x0x6b2jp">2.15</td><td class="odds-nowrp" xodd="3.86" xoid="E-2ns9hxv498x0x0">3.86</td><td class="odds-nowrp" xodd="2.91" xoid="E-2ns9hxv464x0x6b2jq">2.91</td><td class="center info-value">55</td></tr></tbody></table></div>
I have been trying combination of properties to access the data within table but all i get is the initial node containing div.
Here is the code used by me
var html = #urlOddsportal;
HtmlWeb web = new HtmlWeb();
var htmlDoc = web.Load(html);
//var html = new HtmlAgilityPack.HtmlDocument();
//html.LoadHtml(new WebClient().DownloadString(urlOddsportal)); // load a string
var root = htmlDoc.DocumentNode;
var node = root.SelectSingleNode("//div[#id='table-matches']"); //this returns non null
// all of the below functions return null value
var rows = node.SelectNodes(".//tr[#class='odd deactivate']");
var table = root.SelectSingleNode("//table[#class=' table-main']");
var tablerows = node.SelectNodes(".//table/tbody/tr[1]");// [#class='odd deactivate']");
var tabletag = htmlDoc.DocumentNode.SelectNodes("//table[#class='table-main']");
Can someone tell me where i am going wrong.
Thanks
Does this return var = table ?
var table = document.DocumentNode.Descendants("table").FirstOrDefault(_ => _.HasProperty("class", " table-main")
Has property =
public static bool HasProperty(this HtmlNode node, string property, params string[] valueArray)
{
var propertyValue = node.GetAttributeValue(property, "");
var propertyValues = propertyValue.Split(' ');
return valueArray.All(c => propertyValues.Contains(c));
}
If it does work you can try it out on the other nodes returning null
I prefere to use this method as it is easier to read than xcode formulas

get innerHTML from DOM using cheerio

This Meteor server code tries to extract the innerHTML from a html string using cheerio package but the error says that the elements has no method 'size'
What am I doing wrong and how to fix it? Thanks
here is the html;
<span class='errorMsg'>some text </span>
message: (html, typeMsg) => {
let $ = cheerio.load(html);
const selection = 'span.' + typeMsg;
const elements = $(selection);
return elements.size() > 0 ? elements.get(0).innerHTML.trim() : '';
}
After few trials and errors and trying to understand the docs, which cloud benefit from some more explanations.
Option 1
const element = $(selection).eq(0);
return element ? element.text().trim() : '';
Option 2
const element = $(selection).get([0]);
return element ? element.children[0].data.trim() : '';
I used option 1 in this case.
var cheerio = require('cheerio');
var $ = cheerio.load('<b>hello</b> world');
// innerHTML
$('body').html()
// <b>hello</b> world
// outerHTML
$.html($('body'))
// <body><b>hello</b> world</body>
// innerText
$('body').text()
// hello world
docs: https://api.jquery.com/html/#html1
My HTML looked like this:
<div class="col-xs-8">
<b>John Smith</b><br />
<i>Head of Widgets</i><br />
Google<br />
Maitland, FL<br />
123-456-7890<br />
<a
href="mailto:example#example.com"
>example#example.com</a
>
</div>
I wanted to extract the inner html of the div in the context of an "each" loop, so I used this code:
$(this).html()
Which returned
<b>John Smith</b><br />
<i>Head of Widgets</i><br />
Google<br />
Maitland, FL<br />
123-456-7890<br />
<a
href="mailto:example#example.com"
>example#example.com</a
>

SQL where condition is only receiving one word from the value of the field

I need to pass to a where condition a string instead of the id of the row, because of reasons. The problem is that the condition are somehow only catching the first word of the selected value. For example, look at this piece of code:
<select id="brand" name="brand" required>
<option value="Lorem Ipsum Dolor" selected>Lorem Ipsum Dolor</option>
</select>
Then, by echoing the last_query(), the condition will show:
... WHERE `table.column` = `Lorem` ...
Instead of the whole value.
This is my query:
public function find_id_ano_modelo($marca, $modelo, $ano, $comb)
{
$this->db
->select('ano_modelo.id')
->join('modelo', 'modelo.id = ano_modelo.id_modelo')
->join('marca', 'marca.id_marca = modelo.id_marca')
->where('marca.id_marca', $marca)
->where('modelo.modelo', $modelo)
->where('ano_modelo.ano', $ano)
->where('ano_modelo.combustivel', $comb)
->where('marca.tipo = 1');
$query = $this->db->get($this->table);
echo $this->db->last_query();
if ($query) {
foreach ($query->result_array() as $q) {
return $q['id'];
}
}
}
That is being called in my edit method from my controller:
...
$marca = $this->input->post('id_marca');
$modelo = $this->input->post('id_modelo');
$ano = $this->input->post('ano');
$comb = $this->input->post('combustivel');
$data['id_ano_modelo'] = $this->Modelos_model->find_id_ano_modelo($marca, $modelo, $ano, $comb);
....
After discussing it in chat, the error was solved:
The request was being sent via an ajax call and the dropdown was built with:
modelo.append('<option value=' + v.modelo + '>' + v.modelo + '</option>');
The problem was the missing double-quotes around the value. Without them, each word of the value was transformed into an html property:
For this string:
QQ 1.0 ACT 12V 69cv 5p
This was generated:
<option value="QQ" 1.0="" act="" fl="" 12v="" 69cv="" 5p="">QQ 1.0 ACT FL 12V 69cv 5p</option>
Adding qoutes here solved it:
modelo.append('<option value="' + v.modelo + '">' + v.modelo + '</option>');

Why are my inputs not resetting?

The below code generates several forms depending on data returned from the server. Everything generates fine, but after clicking on an AnswerOpenQuestion button the input does not clear/reset. What's going on here?
angularJs code:
var availableInterviewController = function($scope, $http) {
// define initial model
$scope.interviews = [];
// retrieve available interviews
$http.get('/api/UserInterviewsApi/AvailableInterviews')
.success(function(data) {
// update interviews
$scope.interviews = [];
$scope.interviews = data;
});
// define open question answer selection
$scope.Answer = "";
// define multiple choice selection
$scope.selectedChoice = "";
// define answer open question button
$scope.AnswerOpenQuestion = function() {
$scope.Answer = ans;
alert(q.Question + ' and ' + $scope.Answer);
$scope.Answer = ''; // <---This is not clearing/resetting the HTML form inputs
};
// define answer multiple choice button
$scope.AnswerMultipleChoice = function() {
//
};
};
// assign the new controller to the main angular app
myAngApp.controller('availableInterviewCtrl', availableInterviewController);
Html code:
<form class="form-group" ng-repeat="q in inter.Questions">
<fieldset style="display: inline-block;">
<legend>Question {{$index + 1}}</legend>
<!--Open Ended-->
<div class="form-group" ng-show="q.MultipleChoices.length === 0">
<label for="{{'quest-' + $index}}">
<strong class="text-info">{{q.Question}}</strong><br />
</label>
<input name="openQuestion" id="{{'quest-' + $index}}" type="text"
class="form-control" ng-model="Answer" />
<button ng-click="AnswerOpenQuestion()">Answer</button><br />
<span class="text-info">
asked by {{q.AskedByUserName ==
'Administrator' ? 'staff' : q.AskedByUserName}}
</span>
</div>
<!--Multiple Choice Question-->
<div class="form-group" ng-show="q.MultipleChoices.length > 0">
<label for="{{'quest-' + $index}}">
<strong class="text-info">{{q.Question}}</strong>
</label>
<div>
Select an answer:
<label ng-repeat="x in q.MultipleChoices">
<input name="currentChoice" type="radio" value="{{x.Id}}"
ng-model="selectedChoice" />
{{x.Choice}}
</label>
<button ng-click="AnswerMultipleChoice()">Answer</button><br />
<span class="text-info">
asked by {{q.AskedByUserName ==
'Administrator' ? 'staff' : q.AskedByUserName}}
</span>
</div>
</div>
</fieldset>
</form>
UPDATE - Solution
AngularJs:
// define open question answer selection
$scope.OpenAnswer = { Answer: '' };
// define answer open question button
$scope.AnswerOpenQuestion = function (q, ans) {
$scope.OpenAnswer.Answer = ans;
alert(q.Question + ' and ' + $scope.OpenAnswer.Answer);
// clear the input
$scope.OpenAnswer.Answer = '';
};
Html:
<input id="{{'quest-' + $index}}" type="text"
class="form-control" ng-model="OpenAnswer.Answer" />
Don't use the scope as a model instead make an object that wraps the data model and assign it to a property of the scope.
$scope.myModel = {Answer:''}
Also don't use value in most cases ngmodel is all you need for two way binding.
In js strings are immutable so the original reference is not being updated instead a new string is being made, the digest cycle won't see this as a change to the original string.