How to choose unique element in two same model? - javascript

I am trying to select unique element but the problem is there is 2 model with no unique mode, and id is dynamic.
its the html
test spec
it('Rental Car should work ', function() {
let rentalCar = new Hotel();
rentalCar.operator.sendKeys('Eurocar');
rentalCar.carClass.selectValue('M');
rentalCar.pickupTime.sendKeys('12');
rentalCar.DropOfTime.sendKeys('13');
//rentalCar.cancelable.check();
rentalCar.clientAmount.sendKeys('120');
rentalCar.supplierAmount.sendKeys('12');
rentalCar.pickupLocation.sendKeys('berlin');
rentalCar.selectpickOption.click();
browser.sleep(2000);
rentalCar.dropLocation.sendKeys('Han');
browser.sleep(2000);
rentalCar.selectDropOption.click();
browser.sleep(2000);
rentalCar.save();
})
i tried to add first() and last() at the end of page object but its getting error "TypeError: $(...).first is not a function "
class Hotel {
constructor() {
this.operator = element(by.model('$ctrl.item.operator'));
this.carClass = new MdSelect('$ctrl.item.class');
this.pickupTime = element(by.model('$ctrl.item.pickup_time'));
this.DropOfTime = element(by.model('$ctrl.item.return_time'));
//this.cancelable = new MdCheckBox('$ctrl.item.isFlex');
this.clientAmount = element(by.model('$ctrl.item.traveler_item_data[0].line_items[0].gross_amount'));
this.supplierAmount =element(by.model('$ctrl.lineItem.supplier_gross_amount'));
this.pickupLocation = $('md-autocomplete md-autocomplete-wrap md-input-container [aria-label="Pickup location"]');
this.selectpickOption = $('md-virtual-repeat-container md-autocomplete-parent-scope');
this.dropLocation = $('md-autocomplete md-autocomplete-wrap md-input-container [aria-label="Drop-off location"]');
this.selectDropOption = $$('.md-virtual-repeat-container .md-autocomplete-parent-scope '); }
help me to solve this problem.

first() and last() are available on ElementArrayFinder. Your error says that you are trying to use first() on ElementFinder.

if there are two same elements, you can use
element.all(by.model('model')).get(0);
Depending upon the index, you can use get(0), get(1).

Related

Merge or extend JavaScript functions

I am trying to get the values of several input fields and then displaying those values somewhere else on the page using JS functions. I will have 10 input fields, therefore is there a way I can optimize my JS code and write a function to loop through the values of the input fields and display them afterwards? Here are two functions which I wrote for two different fields:
function gotoTask() {
var message = document.getElementById("goto").value;
goto_message.innerHTML = message;
}
function waitTask() {
var message = document.getElementById("wait").value;
wait_message.innerHTML = message;
}
You could write a curry/factory function:
function createTaskFn(el, messageElId) {
return function() {
var message = document.getElementById(messageElId).value;
el.innerHTML = message;
};
}
var gotoTask = crateTaskFn(goto_message, 'goto');
var waitTask = crateTaskFn(wait_message, 'wait');
Give same class to your all inputs , then select them by let inputArr = document.getElementsByClassName('inputsClass') , then loop through inputArr and display their values.
You could store all the ids in an array like so
const inputIds = ['goto', 'wait', ...]
Then you can iterate over that array and call your method like so
inputIds.forEach((id) => {
const message = document.getElementById(id).value;
document.getElementById(`${id}_message`).innerHTML = message;
})
Disadvantage of my implementation: Your ids of the message fields have to have the same structure [id]_message

name.forEach is not a function after button is clicked

I am trying to edit/update current data using the contenteditable attribute which I have successfully enabled onclick. My 'enter' key allows the data to be submitted. However, the console.log reads that a PUT request has been made for a particular list item but without the 'title' or 'isbn' being updated along with it.
Another prominent issue is that my console.log shows books.forEach is not a function, and I have no idea why this is the case since the code inside that function is processed.
HTML ('li' items are solely JS-Generated with a POST request)
<div id="divShowBooks">
<li id="[object HTMLParagraphElement]">
<p id="24" name="anID" placeholder="24">1</p>
<p id="TEST" name="aTitle" placeholder="TEST">TEST</p>
<p id="12345" name="anISBN" placeholder="12345" contenteditable="true">12345</p>
<button>Delete</button>
</li>
</div>
JavaScript
var book_list = document.querySelector('#divShowBooks');
book_list.innerHTML = "";
var books = JSON.parse(this.response);
books.forEach(function (book) {
// Text information to be displayed per item
var id = document.createElement('p');
id.type = 'text';
id.innerHTML = book.id;
var title = document.createElement('p');
title.type = 'text';
title.innerHTML = book.title;
var isbn = document.createElement('p');
isbn.type = 'text';
isbn.innerHTML = book.isbn;
// Defining the element that will be created as a list item
var book_item = document.createElement('li');
// Displays id, title and ISBN of the books from the database
book_item.appendChild(id);
book_item.appendChild(title);
book_item.appendChild(isbn);
// Creates an ID attribute per list item
book_item.setAttribute("id", id)
// Assigns attributes to p items within book items
id.setAttribute("id", book.id)
title.setAttribute("id", book.title)
isbn.setAttribute("id", book.isbn)
// Adding a generic name to these elements
id.setAttribute("name", "anID")
title.setAttribute("name", "aTitle")
isbn.setAttribute("name", "anISBN")
title.addEventListener('click', function (e) {
e.preventDefault();
title.contentEditable = "true";
title.setAttribute("contenteditable", true);
title.addEventListener('keypress', function (e) {
if (e.keyCode === 13) {
e.preventDefault();
xhttp.open("PUT", books_url + '/' + book.id, true);
var editTitle = new FormData() /
editTitle.append("title", document.getElementsByName("aTitle")[0].value)
xhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded')
xhttp.send(); //
}
});
});
UPDATE
I have added the following to my code. This seems to display my database items as an array in the log. But, I am now having a similar issue with Uncaught TypeError: JSON.parse(...).map is not a function:
var params = [
id = 'id',
title = 'title',
isbn = 'isbn',
createdAt = 'createdAt',
updatedAt = 'updatedAt'
];
var books = JSON.parse(this.response).map(function(obj) {
return params.map(function(key) {
return obj[key];
});
});
console.log(books);
UPDATE 2
Here is an image of what I receive in the console.log. The first part displays the original JSON content and the second is my attempt to convert each object into an array.
See Image
You have to make sure that your books variable actually contains an Array after parsing.
Alternatively, but this wouldn't make sense, just to address the "books.forEach is not a function" issue, You can use Object.assign([], this.response);. To make sure that books will contain an array, you wrap it in a try catch and make something like this:
var books = [];
try {
books = Object.assign([], this.response);
} catch (error) {
books = [];
}
books.forEach will then be expected to always work but you have to be careful because something like this could happen:
var myStringObject = "{'myProperty':'value'}";
var myArray = Object.assign([], myStringObject );
//myArray value is ["{", "'", "myProperty", "'", ":", "'", "value", "'", "}"]
Which will leave you having to check the book in your forEach callback if it is correct:
//at the topmost of your forEach callback
if(!book.id) throw BreakException; //A simple break will not work on forEach
This will leave you again with another exception to handle. Or leave you having to use the traditional for loop since you cannot short circuit Array.forEach with a break.
TLDR: make sure books always contains an Array.
You are getting books from JSON.parse(), which means books is an object and not an array.
forEach is an array method.
Try console logging books and look for an array inside of it.

JQuery onclick parameter passing with append

Im currently trying to append a variable amount of text to a list. Each item would need to be clickable with their own value being passed to a function. I cannot seem to get this to work and keep getting a 'Object' is not defined at HTMLAnchorElement.onclick error, where object is the name of the object in the list. Here is the code that I am using for this:
if (user) {
id = user.uid;
ref = firestore.collection("Users").doc(id);
console.log(user);
console.log(ref.get());
ref.get().then(function(doc){
nameString = doc.data().name;
console.log(nameString);
const outputHeader = document.querySelector("#headMain");
const outputInfo = document.querySelector("#genInfo");
outputHeader.innerText = "Welcome " + nameString;
outputInfo.innerText = "Create a class or choose a class from the left";
});
firestore.collection("Users").doc(id).collection("Classrooms").get().then(function(querySnapshot){
querySnapshot.forEach(function(doc){
classNameString = doc.id;
console.log(doc.id, " => ", doc.data());
$("li").append(''+doc.id+'<br/>');
});
});
}
The current testInfo function is as follows:
function testInfo(val){
console.log(val);
}
The following html code cannot work
'+doc.id+'
You are missing the double quotes, so the onclick is executed on the anchor element (the "#")
What you want to do is:
'+doc.id+'

TypeError on split()

I am trying to hide elements based on whether the user has added the class numbers to the database which I am retrieving through json data. If all the class numbers are present on the component I want to hide it.
At the moment I keep getting this error:
TypeError: $(...).data(...).split is not a function
export function VisaToggleComponent() {
let json = {
visa_subclass:[462,500,801]
};
let elements = document.querySelectorAll('[data-visa-hide]');
console.log(elements);
$(elements).each(function() {
let data = json.visa_subclass,
target = $(this).data('visa-hide').split(',').map(Number);
console.log(target);
for (let i in data) {
let val = data[i];
let index = target.indexOf(val);
if(index > -1) {
$(this).hide();
}
}
});
}
split is a method of the String object. Since you're getting
TypeError: $(...).data(...).split is not a function
It means $(this).data('visa-hide') is not a string.
To be honest, I didnt try to understand your code, however if you think $(this).data('visa-hide') is string-like data type you have to change $(this).data('visa-hide').split(',') to String.prototype.split.call($(this).data('visa-hide'), ',')

Check if team already added

I have a page where you can invite teams. Clicking "Invite teams" makes a popup box appear showing a search input. The search-function is AJAX based. When a team is found through your search word(s), you'll have to click on the team whereupon the team will be showed in a "Invited-teams"-box.
It works in a way that when you "add" the team, a hidden input field is generated containing the team's ID as a value. The problem is that with my current code, it is possible to add the same team as many times as you wish. I should be possible to check, if the team can be found in the hidden-input-data. If it already exists, it should not be possible to add the sane team.
My current javascript-code can be found beneath here. Please notice that I have tried to make the code that checks the team, but it doesn't work.
function addTeam(tid) {
// Grab the input value
var teamName = document.getElementById(tid).innerHTML;
var teamID = document.getElementById(tid).id;
// If empty value
if(!teamName || !teamID) {
alert('An error occured.');
} else {
//Tried to do the "team-adlready-added"-test, but it doesn't work
var stored_teams = $t('#store-teams').getElementsByTagName('input');
for (var i = 0; i < stored_teams.length; i++) {
var stored_team = stored_teams[i];
if(stored_team.value == teamID) {
break;
var team_already_added = 1;
}
alert(team_already_added);
}
if((team_already_added) || team_already_added != 1) {
// Store the team's ID in hidden inputs
var store_team = document.createElement('input');
store_team.type = 'hidden';
store_team.value = teamID;
// Append it and attach the event (via onclick)
$t('#store-teams').appendChild(store_team);
// Create the teams with the value as innerHTML
var div = document.createElement('div');
div.className = 'team-to-invite';
div.innerHTML = teamName;
// Append it and attach the event (via onclick)
$t('#teams').appendChild(div);
}
div.onclick = removeTeam;
}
return false;
}
Thanks in advance.
I just want to give you a hint for a possible solution without html elements.
You can create a new functional object for team:
var Team = function (id, name) {
this.name = name;
this.id = id;
}
Create an array which will contain teams:
var TeamList = [];
Add you Teams:
TeamList.push(new Team(1, "Team 1"));
TeamList.push(new Team(2, "Team 2"));
TeamList.push(new Team(3, "Team 3"));
TeamList.push(new Team(4, "Team 4"));
Write a function which loops trough the list of teams and checks with the id if a team already exists:
function containsTeam(id) {
for (var i = 0; i < TeamList.length; i++) {
if (TeamList[i].id == id) {
return true;
}
}
return false;
}
Just check it:
containsTeam(1); //returns true
containsTeam(5); //returns false
Have a look at the jsFiddle DEMO and open the console to see the output.
EDIT: In addition, to remove an element you can write a function which looks pretty much the same as the containsTeam function. Just use array.splice instead of returning true:
function removeTeam(id) {
for (var i = 0; i < TeamList.length; i++) {
if (TeamList[i].id == id) {
TeamList.splice(i, 1);
}
}
}
And remove a team:
removeTeam(3);
Your variable scope is off.
You declare team already added in the wrong spot.
Declare it with team name and team id and it will get you in the right direction

Categories

Resources