PUG playing with index - iteration

After using SO and found a lot of answers to feed my learning process, it's time for me (and because I haven't found any answer to my problem yet) to ask for your help.
I'm learning PUG since some days, and I'm trying to use "each" iteration to create a html/css slideshow (following the project of (shit, can't find the git anymore, too much projects based on this)).
Sorry.
Here's the pug code I made:
.slideshow
each val, index in ['img-1.jpg', 'img-2.jpg', 'img-3.jpg']
input(type="radio" name="ss" id='ss-img-' + index).ss-bullet
.ss-img
img(src=val)
label(for='ss-img-' + *index*).ss-nav-prev Image précédente
label(for='ss-img-' + *index*).ss-nav-next Image suivante
(.classes are just for later styling of the buttons/bullets)
And this is what I'm trying to obtain, in html:
<div class="slideshow">
<input class="ss-bullet" type="radio" name="ss" id="ss-img-0">
<div class="ss-img"><img src="img/img-1.jpg">
<label class="ss-nav-prev" for="ss-img-2">Image précédente</label>
<label class="ss-nav-next" for="ss-img-1">Image suivante</label>
</div>
<input class="ss-bullet" type="radio" name="ss" id="ss-img-1">
<div class="ss-img"><img src="img/img-2.jpg">
<label class="ss-nav-prev" for="ss-img-0">Image précédente</label>
<label class="ss-nav-next" for="ss-img-2">Image suivante</label>
</div>
<input class="ss-bullet" type="radio" name="ss" id="ss-img-2">
<div class="ss-img"><img src="img/img-3.jpg">
<label class="ss-nav-prev" for="ss-img-1">Image précédente</label>
<label class="ss-nav-next" for="ss-img-0">Image suivante</label>
</div>
</div>
Of course as you all noticed, the missing part is in the index:
label(for='ss-img-' + *index*)
part.
Can someone please teach me how to iterate the index to complete this?
(another thing you probably noticed is that i'm still new to javascript, and french)
Thanks!

So, what you need is a simple bit of circular (wrap-around) arithmetic (see also answers to this SO question):
- var arrayLength = 3;
label(for='ss-img-' + ((index + arrayLength - 1) % arrayLength)).ss-nav-prev Image précédente
label(for='ss-img-' + ((index + 1) % arrayLength)).ss-nav-next Image suivante

So with your code added:
.slideshow
each val, index in ['img-1.jpg', 'img-2.jpg', 'img-3.jpg']
input(type="radio" name="ss" id='ss-img-' + index)
.ss-img
img(src=val)
label(for='ss-img-' + ((index + val.length - 1) % val.length)) Image précédente
label(for='ss-img-' + ((index + 1) % val.length)) Image suivante
I'm getting this:
<div class="slideshow">
<input type="radio" name="ss" id="ss-img-0">
<div class="ss-img"><img src="img-1.jpg">
<label for="ss-img-8">Image précédente</label>
<label for="ss-img-1">Image suivante</label>
</div>
<input type="radio" name="ss" id="ss-img-1">
<div class="ss-img"><img src="img-2.jpg">
<label for="ss-img-0">Image précédente</label>
<label for="ss-img-2">Image suivante</label>
</div>
<input type="radio" name="ss" id="ss-img-2">
<div class="ss-img"><img src="img-3.jpg">
<label for="ss-img-1">Image précédente</label>
<label for="ss-img-3">Image suivante</label>
</div>
</div>
(removed the classes to make it more clear)
As you can see, the first and last items are not yet looping as expected. Only the middle one is right.
(And sorry to use 'answer' instead of 'comment', I haven't found a way to write multiples lines code...)
Thanks again for helping!

Here's the final pug code for the one who wants to use it:
.slideshow
- var imgs = ['img/img-1.jpg', 'img/img-2.jpg', 'img/img-3.jpg', 'img/img-4.jpg', 'img/img-5.jpg', 'img/img-6.jpg']
each img, index in imgs
input(type="radio" name="ss" id=('ss-img-' + index) checked=(index === 0)).ss-bullet
.ss-img
img(src=img)
label(for='ss-img-' + ((index + imgs.length - 1) % imgs.length)).ss-nav-prev Image précédente
label(for='ss-img-' + ((index + 1) % imgs.length)).ss-nav-next Image suivante

Related

How to chain selectors in order to get element inside with webdriverio

I have a page with list of products on it.
This is how HTML DOM looks like for one product item:
<div class="module card listing-search-card js-product-card " id="product-entry-123" data-product-id="123" data-toggle-status="open" data-out-of-stock="" data-toggle-isbundle="false" data-load-prices-async="false">
<div class="product-entry__wrapper">
<div class="card__header">
<div class="promotion">
<div class="product-entry__right promotion-card__body on-promotion--banner-offer">
</div>
<a href="/Products/p/123" tabindex="-1">
<picture>
<img class="card__image mobile-img lazyload" src="/medias/image-mobile">
<img class="card__image desktop-img lazyloaded" src="/medias/image-desktop">
</picture>
</a>
</div>
</div>
<div class="product-entry__body-actions-wrapper">
<div class="product-entry__body card__body">
<h3 class="card__title">
Schweppes
</h3>
<div class="product-entry__summary card__description-wrapper">
<div class="product-entry__summary__list">
<div class="card__detail-wrapper">
<div class="product-entry__summary__item card__description-product-detail">
33 x 24</div>
<div class="product-entry__summary__item card__description-product-code">
<span class="product-entry__code">
123</span>
</div>
</div>
<div class="container-type">
box</div>
</div>
</div>
</div>
<div class="cta-container">
<div class="card__amount-wrapper ">
<div class="card__amount">
61,83 € <span class="base-unit">HT/CHACUN</span>
<p class="sales-unit-price is-price">
<span>soit</span> 10,00 €
</span></span></p>
</div>
</div>
<div class="add-to-cart__footer add-to-cart__action">
<div class="success-overlay">Add to cart</div>
<div class="add-to-cart__action--active">
<div class="form-quantity__wrapper quantity-action quantity-action__wrapper"
data-form-quantity-id="123">
<div class="form-quantity ">
<button class="form-quantity__decrease quantity-action__decr icon-Minus disabled" type="button"
tabindex="-1" aria-label="decrement" data-form-quantity-decrement="">
</button>
<input id="product-123" class="form-quantity__input form-control quantity-action__value js-
quantity-input-typing" name="product-123" type="text" value="1" maxlength="4" data-price-
single="10.00" data-price-currency="€" data-parsley-range="[1,9999]" data-form-quantity-times="1"
data-parsley-multiplerange="1" data-parsley-type="integer" data-parsley-validation-threshold="1"
required="">
<button class="form-quantity__increase quantity-action__incr icon-Add-to-list" type="button"
tabindex="-1" aria-label="increment" data-form-quantity-increment="">
</button>
</div>
<span class="form-quantity__update" data-form-quantity-success=""></span>
</div>
<div class="add-to-cart__total">
<button class="button button--primary js-addToCart" role="button" title="Add
to cart" data-product-id-ref="123" data-modal-trigger="" data-modal-target="#add-to-cart-modal" data-
modal-before-trigger="addToCart" data-component-id="product list" tabindex="-1">
<div class="button__text">
<span class="button__text-add js-added-price">Add</span>
<span class="button__text-to-cart js-added-price">to cart</span>
</div>
<span class="button__text js-added-price mobile-only">Add</span>
</button>
</div>
</div>
</div>
<div class="add-to-template">
<button class="add-to-template--button button js-addToNewTemplate" type="button" data-modal-
trigger="" data-modal-target="#add-to-template-modal" data-modal-before-
trigger="openAddToTemplateModal" data-product-code="123">
<span>Add to list</span>
</button>
</div>
</div>
</div>
</div>
I am calling this function:
isSortedAlphabeticallyAscending($$('div.js-product-card'));
And the function implementation is:
isSortedAlphabeticallyAscending(list) {
for (let i = 0; i < (list.length - 1); i++) {
let outOfStockCurrent = list[i].getAttribute('data-out-of-stock');
let outOfStockNext = list[i + 1].getAttribute('data-out-of-stock');
let idCurrent = list[i].getAttribute('id');
let idNext = list[i + 1].getAttribute('id');
console.log("outOfStockCurrent " + outOfStockCurrent + " " + idCurrent);
console.log("outOfStockNext " + outOfStockNext + " " + idNext);
let productIdCurrent = idCurrent.split('-').pop();
let productIdNext = idNext.split('-').pop();
let currentText = list[i].$('a[href*="' + productIdCurrent + '"]').getText();
let nextText = list[i+1].$('a[href*="'+ productIdNext + '"]').getText();
console.log("currentText " + currentText);
console.log("nextText " + nextText);
if(outOfStockCurrent === "true" || outOfStockNext === "true") continue;
if (currentText > nextText) return false;
}
return true;
}
I ignore out of stock products since they are always at the bottom of the page.
But the list[i].$('a[href*="' + productIdCurrent + '"]').getText() is always returning empty text.
I would like it to get "Schweppes" text, i.e. product name.
Is there a way to chain somehow differently part with .$a[href ...] to get the text from the <a> tag inside the <div> element of the list of products using webdriverio 5?
Thanks!
The above selector list[i].$('a[href*="' + productIdCurrent + '"]').getText() targeted 2 elements.
What I needed to go one div further and find it there:
list[i].$('div.product-entry__body-actions-wrapper').$('a[href*="' + productIdCurrent + '"]').getText()
And voila, text appeared :)
Hope it will help someone with the similar issue :D

How can I use loop index in an attribute?

I'm new to Vue, and can't achieve quite a simple thing. I want to be able to use the loop index to set a unique name for an attribute. For example, I want to set the ID attribute to something like this: id="somename{{index}}", but that gives an interpolation inside attributes error.
<div v-for="(dt, index) in driveTrain" >
<input type="radio" id="driveTrain-{{index}}" >
<label for="driveTrain-{{index}}">{{dt}}</label>
</div>
you can bind the id dynamically using v-bind directly:
<div v-for="(dt, index) in driveTrain" >
<input type="radio" :id="'driveTrain'+index">
<label :id="'driveTrain'+index">{{dt}}</label>
</div>
Or:
bind it using template literals :
<div v-for="(dt, index) in driveTrain" >
<input type="radio" :id="`driveTrain${index}`">
<label :id="`driveTrain${index}`">{{dt}}</label>
</div>

How to bind the values of two types of inputs to a single array in Vuejs

In a web form, using Vuejs, I would like to implement a multiple choice question with a sub-question for each item.
For instance, the question could look like this:
What type of vehicle do you use, and how often ?
A) Aeroplane (chekbox), Every day / Once a month / once a year (radio),
B) Train (checkbox), Every day / Once a month / Once a year (radio),
C) Donkey (checkbox), Every day / Once a month / Once a year (radio),
D) (and so on).
I can imagine that my html could look something like this :
<div class="form-group">
<div class="line" v-for="(type, index) in listOfVehicles">
<input type="checkbox" v-bind:value="index" v-bind:id="index" v-model="???">
<label v-bind:for="index">{{type}}</label>
<div class="subquestion" v-for="(sub, id) in listOfSubQuestions">
<input type="radio"
v-bind:value="id"
v-bind:id="'sub-' + index + '-' + id"
v-model="???">
<label v-bind:for="'sub-' + index + '-' + id">{{sub}}</label>
</div>
</div>
</div>
where my Vue instance would have listOfVehicles and listOfSubQuestions as arrays in my data.
Ideally, I would like all the respondent's input to be stored in a single array called for instance answers.
As an example, if answers A and C have been ticked, answers could look something like: [{vehicle: 'A', frequency: 'Once a year'},{vehicle: 'C', frequency: 'Every day'}].
But I have no clue how to make this work.
I quickly made something if this is what you need. Its my first time answering a question hope this can help you out. You can add a button and store a new object every-time you click the button,
which can result something like the example you mentioned.
new Vue({
el: "#app",
data: {
vehicle: [],
frequency: '',
result: []
},
methods: {
save() {
const result = {
vehicle: this.vehicle,
frequency: this.frequency
}
this.result.push(result)
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<h2>What type of vehicle do you use, and how often ?</h2>
<div>
<label for="plane">Aeroplane</label>
<input id="plane" type="checkbox" value="aeroplane" v-model="vehicle">
<label for="car">car</label>
<input id="car" type="checkbox" value="car" v-model="vehicle">
<label for="train">train</label>
<input id="train" type="checkbox" value="train" v-model="vehicle">
<div>
<label for="plane">everyday</label>
<input type="radio" name="options" value="everyday" v-model="frequency">
<label for="plane">monthly</label>
<input type="radio" name="options" value="monthly " v-model="frequency">
<label for="plane">yearly</label>
<input type="radio" name="options" value="yearly" v-model="frequency">
</div>
<button #click="save">submit</button>
<p>{{result}}</p>
</div>
</div>

Unable to find element using protactor which have same classes

I have one check box and two links with same classes & same Div.During the automation testing using protractor, i want to click on check box but it click on Links.
i am writing this code but its not working, please provide a solution.
Code:
element(by.id('Remember')).click();
[1
please find HTMl code:-
<div class="input-field">
<div class="pas_rembr">
<input name="remember" id="Remember" class="css-checkbox ng-dirty ng-valid-parse ng-touched ng-not-empty ng-valid ng-valid-required" ng-model="rememberMe" type="checkbox" ng-required="true" required="required">
<!-- <label for="Remember" class="css-label">I agree with the <a class="text_link" target="_blank" ng-href="{{baseUrl}}terms-conditions">Terms & Conditions</a>.</label> -->
<label for="Remember" class="css-label">I have read and I agree with <a class="text_link" target="_blank" ng-href="/lmd/terms-conditions" href="/lmd/terms-conditions">Terms and Conditions</a> and the <a class="text_link" target="_blank" ng-href="/lmd/privacy" href="/lmd/privacy">Privacy Policy</a> of this site.</label>
</div>
<span class="errorForm ng-hide" ng-show="(memberForm.remember.$dirty || submitted) && ((memberForm.remember.$error.required))">
<span class="errorForm ng-scope ng-hide" ng-show="memberForm.remember.$error.required" translate="TERAMS_CONDITION_IS_REQUIRED">Terms and condition is required</span>
</span>
</div>
Try this:-
var el = element(by.css('label[for="Remember"]'));
browser.actions().mouseMove(el, {x: 20, y: 3}).click().perform();
For your tests, the CSS selector would be
element = $$('label.css-label > a:nth-child(2)');
This should be able to click on the second a child of the label element.

How to Select Radio button inside Fieldset using behat

Can any one please help me out how to select a radio button if it is inside a fieldset??
I can access individual radio button using foreach but when i try to select it or click it its giving some Ajax error.
HTML code is given below
I have tried to select it with radio button's label as well as given in above comment but not able to select it.
<fieldset id="edit-cvs-options" class="form-wrapper">
<legend>
<div class="fieldset-wrapper">
<div class="ios-content" style="display: none;">test</div>
<div class="form-item form-type-radio form-item-use-stored">
<label for="edit-use-stored">
<span>test</span>
<input id="edit-use-stored" class="form-radio" type="radio" name="use_stored" checked="TRUE" value="on" display-title-fix="1"/>
</label>
</div>
<fieldset id="edit-cvs-1" class="form-wrapper" style="display: inline-block;">
<div>
<div class="form-item form-type-radio form-item-use-uploaded">
<label for="edit-use-uploaded">
<span>test</span>
<input id="edit-use-uploaded" class="form-radio" type="radio" name="use_uploaded" display-title-fix="1" value="off"/>
</label>
</div>
</div>
</fieldset>
This is my Behat step definition:
$session = $this->getSession(); // get the mink session
$escapedValue = $session->getSelectorsHandler()->xpathLiteral('use_uploaded');
$radioButton = $session->getPage()->find('named', array('radio', $escapedValue));
$radioButton ->click();