<div>
<p>
<a class="article-link" href="/title1">Title 1</a>
<a class="article-link" href="/title1">year1</a>
</p>
<p>
<a class="article-link" href="/title2">Title 3</a>
<a class="article-link" href="/title2">year2</a>
</p>
<p>
<a class="name-link" href="/title3">Title 3</a>
<a class="name-link" href="/title3">year1</a>
</p>
</div>
I need to automate some function in a website. I want to redirect to the link, if you know the title AND the year, using javascript.
for example: I want to be redirected to the link of title3 and year1.
I tried with this:
function picktitle() {
chrome.storage.sync.get('title', function(data) {
var items = document.getElementsByClassName('article-link');
for(i = 0; i < items.length; i++) {
if((items[i].innerHTML).includes(title)) {
chrome.runtime.sendMessage({redirect: items[i].href});
break;
}
}
});
}
but it choose only the first parameter and i need that it choose the href based on both title and year.
I hope I explained myself.
I'm really sorry if im misunderstanding this, but wouldn't using the && keyword in your if statement be the solution? For example:
if (statement1 && statement2) // only runs if both statement1 AND statement2 are true
// do stuff
Also, maybe select the parent element and check to see if it's children have two elements with the required text properties:
function picktitle() {
chrome.storage.sync.get('title', function(data) {
var items = document.getElementsByClassName('article-link');
for(i = 0; i < items.length; i++) {
if(
// Checks if the parent contains the title and the year
(items[i].parentElement.innerText).includes(title) &&
(items[i].parentElement.innerText).includes(year)) {
chrome.runtime.sendMessage({redirect: items[i].href});
break;
}
}
});
}
I also changed innerHTML to innerText because you probably don't need all the html code with it too.
Related
i work with prestashop1.7. The Search by Brand works perfectly under the form "dropdown list" in the module ps_facetedSearch.
I need to override this search instead of dropdown i need an input field, So i think that the solution can be to search if the inputed text is exist in the dropdown list. this is my essay but the console display no despite console log on txtValue and inpted showContent of these variables. that's why i need your help concerning the script js itself that must test if inputed text exist in the dropdown list.
code html of the module faceted search
<div class="dropdown-menu" id="dropdown-menu">
<a rel="nofollow" href="http://archivartshop.local/fr/2-accueil?q=Marque-Naim+Ameur" class="select-list"> Naim Am(1)</a>
<a rel="nofollow" href="http://archivartshop.local/fr/2-accueil?q=Marque-Sonia+Mili" class="select-list"> Sonia Mili (1) </a>
<a rel="nofollow" href="http://archivartshop.local/fr/2-accueil?q=Marque-Yosr+Ben+Hammouda" class="select-list"> Yosr Ben Houda(2)</a>
</div>
My essay script js
function mFn(){
divLi = document.getElementById("dropdown-menu");
linka = divLi.getElementsByTagName("a");
for (i = 0; i < linka.length; i++) {
var txtValue = linka[i].textContent ;
// console.log(txtValue); content displayed
var inpted = $('#search_input').val();
// console.log(inpted);content displayed
if( txtValue === inpted)
{
console.log("it_works");
}
else {
console.log("No !!");
}
}
}
I would be very grateful for your help
Now it works for me
function mFn(){
divLi = document.getElementById("dropdown-menu");
linka = divLi.getElementsByTagName("a");
for (i = 0; i < linka.length; i++) {
var txtValue = linka[i].textContent ;
// console.log(txtValue); content displayed
var inpted = $('#search_input').val();
// console.log(inpted);content displayed
if( txtValue.includes(inpted) )
{
console.log("it_works");
}
else {
console.log("No !!");
}
}
}
Im trying to achieve this piece of code but in my console it says thing is null which is weird because when I look in the console, sessionStorage isn't empty...
$(".btn-alert").click(function(){
var identifierOfSpan = $(this > "span").text();
for(var prop in sessionStorage){
var thing = JSON.parse(sessionStorage.getItem(prop))
if(thing.id == identifierOfSpan){
sessionStorage.removeItem(prop);
}
}
$(this).closest(".voyages").remove();
if(sessionStorage.length == 0){
alert("Message!");
location.href="reservation.html"
}
});
the button is supposed to delete the div and the sessionStorage item which looks like this
Html :
<div class="voyages">
<button class="btn btn-alert btn-md mr-2" tabindex="-1">delete the flight</button>
<span>ID : 4224762</span>
<div class="infos">
<img src="img/angleterre.jpg" alt="maroc">
<div>
<ul>
<li><h5>Angleterre, Londres (LON)</h5></li>
<li><h5>2 adulte(s)</h5></li>
<li><h5> Aucun enfants </h5></li>
<li><h5>Type : Couple</h5></li>
</ul>
</div>
</div>
<hr>
<h3>Options</h3>
<ul>
<li>voiture : 0</li>
<li>Hotel : 0 </li>
</ul>
<hr>
<h3>Prix :3713$</h3>
If I'm reading your question correctly, you want to...
Click on a button
Find the first sibling <span> element and parse a number out of its text content
Remove all sessionStorage items (JSON serialized objects) with matching id properties
For the ID, I highly recommend adding some data directly to the <button> to help you identify the right record. If you can, try something like
<button class="btn btn-alert btn-md mr-2" data-voyage="4224762"...
Try something like this
$('.btn-alert').on('click', function() {
const btn = $(this)
const id = btn.data('voyage')
// or, if you cannot add the "data-voyage" attribute
const id = btn.next('span').text().match(/\d+$/)[0]
// for index-based removal, start at the end and work backwards
for (let i = sessionStorage.length -1; i >= 0; i--) {
let key = sessionStorage.key(i)
let thing = JSON.parse(sessionStorage.getItem(key))
if (thing.id == id) {
sessionStorage.removeItem(key)
}
}
// and the rest of your code
btn.closest(".voyages").remove();
if(sessionStorage.length === 0) {
alert("Message!");
location.href = 'reservation.html'
}
})
The problem with using a for..in loop on sessionStorage is that you not only get any item keys added but also
length
key
getItem
setItem
removeItem
clear
I am new to using nightwatch.js.
I want to get a list of elements and verify text value of each and every element with a given string.
I have tried :
function iter(elems) {
elems.value.forEach(function(element) {
client.elementIdValue(element.ELEMENT)
})
};
client.elements('css selector', 'button.my-button.to-iterate', iter);
For another stackoverflow question
But what I am using right now is
waitForElementPresent('elementcss', 5000).assert.containsText('elementcss','Hello')
and it is returning me the output
Warn: WaitForElement found 5 elements for selector "elementcss". Only the first one will be checked.
So I want that it should verify text value of each and every element of list.
All the things can not be done by nightwatch js simple commands , so they have provided the custom command means selenium protocol. Here you can have all the selenium protocol. I have used following code to assert text value of each and every element with a given string "text". Hope it will help you
module.exports = {
'1. test if multiple elements have the same text' : function (browser) {
function iter(elems) {
elems.value.forEach(function(element) {
browser.elementIdText(element.ELEMENT, function(result){
browser.assert.equal(result.value,'text')
})
})
};
browser
.url('file:///home/user/test.html')
.elements('tag name', 'a', iter);
}
};
My HTML snippet
<div id="test">
<a href="google.com" class='red'> text </a>
<a href="#" class='red'> text </a>
<a href="#" class='red'> text 1</a>
</div>
I was able to do it as :
.elements('css selector', 'cssValue', function (elements) {
for(var i=0;i<elements.value.length;i++){
var elementCss = 'div.search-results-item:nth-child(' + (i+1) + ') span';
client.assert.containsText(elementCss,'textValue');
}
})
Put your function iter in a for loop and before that use
client.elements('css selector', '#CollectionClass', function (result) {
if(result.value.length > 1) {
var count;
for(count=1; count<result.value.length; count++) {
result.value.forEach(function(element) {
client.elementIdValue(element.ELEMENT);
client.elementIdText(selectedHighlight.ELEMENT, function(resuddlt) {
this.assert.equal(typeof resuddlt, "object");
this.assert.equal(resuddlt.status, 0);
this.assert.equal(resuddlt.value, "your value");
});
}
}
}
};
You have stated what you have tried (which is good) but you haven't presented us with sanitized HTML that demonstrates the problem (which reduces precision in possible answers).
There are many ways in HTML to contain information, and the built-in Nightwatch containsText will serialize any text it finds within a structure that contains substructures.
So for example, if you have as Juhi suggested,
<div id="test">
<a href="google.com" class='red'> text </a>
<a href="#" class='red'> text </a>
<a href="#" class='red'> text 1</a>
</div>
Then the assertions
.verify.containsText('#test', ' text ') // first one
.verify.containsText('#test', ' text ') // second one
.verify.containsText('#test', ' text 1') // third one
will pass, because they each verify the specific information without the need for writing a loop. Nightwatch will look at the test element and serialize the elements into the string text text text 1
Now if you need a loop for other reasons this is all academic, but your original question seemed to be targeted at how to get the text information out, not necessarily how to execute one possible solution to the problem (which is writing a loop).
I created custom assertions - custom-assertions/hasItems.js with content:
exports.assertion = function hasItems(selector, items) {
this.message = `Testing if element <${selector}> has items: ${items.join(", ")}`;
this.expected = items;
this.pass = selectedItems => {
if (selectedItems.length !== items.length) {
return false;
}
for (let i = 0; i < selectedItems.length; i++) {
if (selectedItems[i].trim() !== items[i].trim()) {
return false;
}
}
return true;
};
this.value = res => res.value;
function evaluator(_selector) {
return [...document.querySelectorAll(_selector)].map(
item => item.innerText
);
}
this.command = cb => this.api.execute(evaluator, [selector], cb);
};
I have a poll application, in which a user can vote for an option in a given poll. in the html template, i use ng-show to show weather the user has voted for this option or this poll or if its an unvoted poll for the user:
<div data-ng-repeat="option in poll.poll_options" class="list-group-item">
<span data-ng-if="option.option_thumb == '2'" class="glyphicon glyphicon-thumbs-up"></span>
<span data-ng-if="option.option_thumb == '1'" class="glyphicon glyphicon-thumbs-down"></span>
<div data-ng-show="optionVoted(option,authentication.user._id)">
<span data-ng-bind="option.option_text"></span>
</div>
<div data-ng-hide="optionVoted(option,authentication.user._id)">
<div data-ng-show="pollVoted(poll._id,votes)">
<a data-ng-click="updateVote()">
<span data-ng-bind="option.option_text"></span> - update
</a>
</div>
<div data-ng-hide="pollVoted(poll._id,votes)">
<a data-ng-click="createVote(poll,option,authentication.user._id,$index)">
<span data-ng-bind="option.option_text"></span> - new
</a>
</div>
</div>
<span class="option-votes"> - {{option.votes.length}}</span>
</div>
these are the above mentioned functions to determine if the option / poll has been voted by the user:
// check if option is voted
$scope.optionVoted = function(option,userId){
for (var i = 0; i < option.votes.length; i++){
if (option.votes[i].user === userId){
return true;
}
}
};
//check if poll is voted
$scope.pollVoted = function(pollId,votes){
for (var i = 0; i < votes.length; i++){
if (votes[i].poll === pollId){
return true;
}
}
}
and here is the function to create a new vote:
// create a vote
$scope.createVote = function(poll,option,userId,index){
var vote = new Votes({
user:userId,
poll:poll._id,
poll_option:option._id
});
vote.poll_option_id = option._id;
vote.$save(function(vote){
option.votes.push(vote);
$scope.$apply();
}, function(errorResponse) {
$scope.error = errorResponse.data.message;
});
}
what happens on the front end, is that the option which has been now voted is updated (not showing an a tag anymore). what i need, is that the other options in the poll will update as well, and now instead of create() they will show update(), without refreshing the page.
how can I get the other html DOM elements of options in the poll to update?
In html, replace the functions in ng-show by an object property :
ng-show="option.voted", for example.
and update option.voted in createVote function.
(adapt this with userId etc.)
Make sure you are pushing the new vote onto the correct object in the scope. It looks like you are displaying data from $scope.poll.poll_options in your view, but you are adding to options.votes in your createVote function.
This question already has answers here:
How to add a class to a given element?
(28 answers)
Closed 9 years ago.
I need to change the class of each href item depending on its value.
I have this code.
<body onload="myFunction()">
<div class="indi-download">
<div class="pull-left">
<h6 class="file" id="file-display-id">%file_display_name%</h6>
</div>
<div class="pull-right">
<a class="download-link" id="download_link" href="%file_url%">Download</a>
</div>
</div>
</body>
In getting the href item on class download-link, I used this javascript code.
function myFunction()
{
var anchors = document.querySelectorAll('a.download-link');
for (var i = 0; i < anchors.length; i++) {
var url = anchors[i].href;
var splitfile = url.split('.').pop();
if(splitfile=='pdf'){
//class="file" would be class="pdf-file"
}else if(splitfile=="docx"){
//class="file" would be class="docx-file"
}else{
//other file format...
}
}
}
on Inspect Element, Something this kind of output.
Element 1 ---
<div class="indi-download">
<div class="pull-left">
//Changed into pdf-file
<h6 class="pdf-file" id="file-display-id">Sample PDF 1</h6>
</div>
<div class="pull-right">
<a class="download-link" id="download_link" href="http://mysite-
info/download/files/file1.pdf">Download</a>
</div>
</div>
Element 2 ---
<div class="indi-download">
<div class="pull-left">
//Changed into docx-file
<h6 class="docx-file" id="file-display-id">Sample docx 1</h6>
</div>
<div class="pull-right">
<a class="download-link" id="download_link" href="http://mysite-
info/download/files/file2.docx">Download</a>
</div>
</div>
How to achieve this kind of output? Changing the classes that depends on the values on href. Any Idea?
If you can use jQuery, I think something like this should work:
function myFunction()
{
var anchors = document.querySelectorAll('a.download-link');
for (var i = 0; i < anchors.length; i++) {
var url = anchors[i].href;
var splitfile = url.split('.').pop();
if(splitfile=='pdf'){
$(anchors[i]).removeClass('file');
$(anchors[i].addClass('pdf-file');
}else if(splitfile=="docx"){
$(anchors[i]).removeClass('file');
$(anchors[i]).addClass('docx-file');
}else{
//other file format...
}
}
}
The class attribute is mapped to the className property so as not to clash with the ECMCAScript future reserved word class, so you want something like:
anchors[i].className = 'docx-file';.
Applied to your example, you can do something like:
var classNames = {pdf:'pdf-file', docx:'docx-file'};
...
anchors[i].className = classNames[splitfile];
and to accommodate a default:
anchors[i].className = classNames[splitfile] || 'default-class';
just in case splitfile doesn't match one of the expected values. And the entire function is:
function myFunction() {
var anchors = document.querySelectorAll('a.download-link');
var classNames = {pdf:'pdf-file', docx:'docx-file'};
for (var i = 0; i < anchors.length; i++) {
var url = anchors[i].href;
var splitfile = url.split('.').pop();
anchors[i].className = classNames[splitfile] || 'default-class';
}
}