How to make the dropdown option of a select box - javascript

I'm building a train web booking project. Now I need to build a selectbox and the option value is varied based on the booking form.
//select-box
<custom-select-box
label="Travel"
v-model="form.InfantWithAdult"
:items="travel"
></custom-select-box>

Try with forEach:
travelWith() {
let travellerlist = [];
let adults = this.passengers.filter(
(x) =>
x.PaxType === "ADT" &&
x.SSR.Outbound.filter((y) => {
return y.codeType === "INFT";
}).length > 0
);
if (adults.length > 0) {
let nr = 1;
let travel = null;
// 👇 loop all adults and add to travellerlist array
adults.forEach(adult => {
if (!adult.FirstName) {
travel = `Adult ${nr++}`;
} else if (adult.FirstName !== "" && adult.LastName !== "") {
travel = `Adult ${nr++} ${adult.Title} ${adult.FirstName} ${adult.LastName}`;
}
travellerlist.push(travel);
})
}
return travellerlist;
},

Related

Star Rating Js + html with symfony

I'm working on a project with symfony 4. I want to implement a star rating system. I display 5 stars in each row in a table. I have two problems, one is more important than the other.
So the first issue is that I want to be able to retrieve the value of the star I selected. If I select 5 stars, I want to get that value back in my entity controller.
The second issue is that, currently, let's say I have 5 items in my table, so 5 rows. Currently, if I select 5 stars in one row it's selected for all rows and I can't select another value anymore. So, it's global or something.
Here is the javascript I'm using:
<script>
const stars = document.querySelectorAll('.star');
let check = false;
stars.forEach(star => {
star.addEventListener('mouseover', selectStars);
star.addEventListener('mouseleave', unselectStars);
star.addEventListener('click', activeSelect);
})
function selectStars(e) {
const data = e.target;
const etoiles = priviousSiblings(data);
if (!check) {
etoiles.forEach(etoile => {
etoile.classList.add('hover');
})
}
}
function unselectStars(e) {
const data = e.target;
const etoiles = priviousSiblings(data);
if (!check) {
etoiles.forEach(etoile => {
etoile.classList.remove('hover');
})
}
}
function activeSelect(e) {
if (!check) {
check = true;
document.querySelector('.note').innerHTML = 'Note ' + e.target.dataset.note;
}
}
function priviousSiblings(data) {
let values = [data];
while (data === data.previousSibling) {
if (data.nodeName === 'I') {
values.push(data);
}
}
return values;
}
</script>
And Here is the twig.html I'm displaying:
<td>
<i class="star" data-note="1">★</i>
<i class="star" data-note="2">★</i>
<i class="star" data-note="3">★</i>
<i class="star" data-note="4">★</i>
<i class="star" data-note="5">★</i>
<i class="note">Note:</i>
</td>
I want to be able to retrieve the value once I made a selection, and to have a different selection for each row I have.
The problem is with the "mouseover" and "mouseleave" event handlers - selectStars and unselectStars. In "selectStars", you are adding the class to only one star. And in "unselectStars", you were not resetting, or applying the "remove" class method to other stars.
Anyway, here is how I have achieved what you are trying to do:
const ratings = document.querySelectorAll('.rating');
ratings.forEach(rating =>
rating.addEventListener('mouseleave', ratingHandler)
);
const stars = document.querySelectorAll('.rating .star');
stars.forEach(star => {
star.addEventListener('mouseover', starSelection);
star.addEventListener('mouseleave', starSelection);
star.addEventListener('click', activeSelect);
});
function ratingHandler(e) {
const childStars = e.target.children;
for(let i = 0; i < childStars.length; i++) {
const star = childStars.item(i)
if (star.dataset.checked === "true") {
star.classList.add('hover');
}
else {
star.classList.remove('hover');
}
}
}
function starSelection(e) {
const parent = e.target.parentElement
const childStars = parent.children;
const dataset = e.target.dataset;
const note = +dataset.note; // Convert note (string) to note (number)
for (let i = 0; i < childStars.length; i++) {
const star = childStars.item(i)
if (+star.dataset.note > note) {
star.classList.remove('hover');
} else {
star.classList.add('hover');
}
}
}
function activeSelect(e) {
const parent = e.target.parentElement
const childStars = parent.children;
const dataset = e.target.dataset;
const note = +dataset.note; // Convert note (string) to note (number)
for (let i = 0; i < childStars.length; i++) {
const star = childStars.item(i)
if (+star.dataset.note > note) {
star.classList.remove('hover');
star.dataset.checked = "false";
} else {
star.classList.add('hover');
star.dataset.checked = "true";
}
}
const noteTextElement = parent.parentElement.lastElementChild.children.item(0)
noteTextElement.innerText = `Note: ${note}`;
}
You might notice I have a .rating class component. This is a div which I have created to hold all these "stars". Here is a link to a codepen I have created. Feel free to play around with it.
And as a note, please provide codepen (or any other) demos so that we can debug a bit better and faster.
I hope the codepen link would help you solve your problem.

JavaScript dropdown menu filter: Can I add multiple values in the "data-" attribute?

I am trying to create dropdown filters using JavaScript. I would like to add more values to "data-subject" using comma. Could you explain how to attribute multiple values in the JavaScript below?
Thanks!
<div class="col-md-3 col-6 property-item" data-grade="prek" data-type="lesson" **data-subject="eng,sci"** >
< script >
$("select.grade, select.type, select.subject").change(update);
function update() {
var resourceGrade = $('select.grade').val();
var resourceType = $('select.type').val();
var resourceSubject = $('select.subject').val();
$('.property-load-section')
.find('.property-item')
.hide()
.filter(function() {
var okResourceGrade = true;
if (resourceGrade !== "all") {
okResourceGrade = $(this).attr('data-grade') === resourceGrade;
}
var okResourceType = true;
if (resourceType !== "all") {
okResourceType = $(this).attr('data-type') === resourceType;
}
var okResourceSubject = true;
if (resourceSubject !== "all") {
okResourceSubject = $(this).attr('data-subject') === resourceSubject;
}
console.log(okResourceSubject);
return okResourceGrade && okResourceType && okResourceSubject;
})
.fadeIn('fast');
}
< /script>
try this
okResourceSubject = $(this).attr('data-subject').split(',').includes(resourceSubject);
split(',') will create an array with all the values ​​separated by a comma

Object value replacing existing object value - Javascript

I'm trying to create an object with an array of multiple objects inside it, each inner-object representing a card.
I initialise all three outside of a forEach() loop, push each item into the array and then assign that array to a key in my outer-object:
const cart = {};
const cartItems = [];
const cartItem = {}
cart['cart-items'] = cartItems;
cartItems.push(cartItem);
Inside the forEach() I take the card data, every time that cards button is clicked, and assign it to the inner-object:
///forEach() with 'click' event-handler for the buttons...
if (cartItem.id !== currentCardId) {
cartItem['id'] = currentCardId;
cartItem['name'] = currentCardName;
cartItem['price'] = this.dataset.cardPrice;
cartItem['quantity'] = 1;
} else {
cartItem.quantity = cartItem.quantity + 1;
}
///...end of forEach()
This increments the 'quantity' of the 'card' if I click the same button multiple times, but when I click on a separate button it overwrites the existing card and it's 'quantity' value.
I understand if I initialise cartItem and cartItems inside the loop it prevents this overwriting, but then the cards 'quantity' doesn't increment, it just creates a separate object with a 'quantity' of '1'.
Any idea how I can work around this?
Edit
Complete code:
addCartBtn.forEach(i => {
i.addEventListener('click', function(e) {
let currentCardId = this.dataset.cardId;
let currentCardName = this.dataset.cardName;
let currentCardQuantity = 0;
let currentCardPrice;
let removeCartItem = document.getElementsByClassName('remove-cart-item');
if (cartItem.id !== currentCardId) {
cartItem['id'] = currentCardId;
cartItem['name'] = currentCardName;
cartItem['price'] = this.dataset.cardPrice;
cartItem['quantity'] = 1;
} else {
cartItem.quantity = cartItem.quantity + 1;
}
if (this.dataset.cardPrice >= 1) {
currentCardPrice = '£' + this.dataset.cardPrice;
} else {
currentCardPrice = this.dataset.cardPrice + 'p';
}
if (currentCardName.length > 10) {
currentCardName = currentCardName.substring(0, 9) + '...';
}
if (document.getElementById(`${currentCardId}`)) {
cartItems.forEach(i => {
if (currentCardId === i) {
currentCardQuantity += 1;
document.getElementById(
`${currentCardId}`
).innerHTML = `x${currentCardQuantity}`;
} else {
document.getElementById(`${currentCardId}`).innerHTML = 'x1';
}
});
} else {
dropdownCheckoutContainer.innerHTML += `<div class="dropdown-card" id="remove-${currentCardId}"><div class="dropdown-card-display"><p class="remove-${currentCardId}"><i class="fa fa-minus-square remove-cart-item" data-remove-id="${currentCardId}"></i>${currentCardName}</p></div><div class="dropdown-quantity"><p class="remove-${currentCardId}" id="${currentCardId}">x1</p></div><div class="dropdown-price"><p class="remove-${currentCardId}">${currentCardPrice}</p></div><div class="dropdown-hidden-id"><input class="remove-${currentCardId}" type="hidden" name="${currentCardId}" data-remove-id="${currentCardId}"></div></div>`;
}
if (dropdownCheckoutContainer.childElementCount >= 7) {
dropdownCheckoutContainer.style.overflow = 'scroll';
dropdownCheckoutContainer.style.borderBottom =
'1px solid rgba(255, 98, 0, 0.5)';
}
if (dropdownCheckoutContainer.childElementCount > 1) {
notificationIconContainer.style.display = 'flex';
notificationIcon.innerHTML =
dropdownCheckoutContainer.childElementCount - 1;
}
for (const i of removeCartItem) {
i.addEventListener('click', function(e) {
let btnId = this.dataset.removeId;
let currentRow = document.getElementById(`remove-${btnId}`);
let idIndexes = [];
if (dropdownCheckoutContainer.childElementCount > 1) {
dropdownCheckoutContainer.removeChild(currentRow);
}
notificationIcon.innerHTML = notificationIcon.innerText - 1;
if (!(dropdownCheckoutContainer.childElementCount >= 7)) {
dropdownCheckoutContainer.style.borderBottom = 'none';
if (checkoutFull.childElementCount === 1) {
checkoutFull.innerHTML = '';
}
}
cartItems.forEach(i => {
if (i === btnId) {
idIndexes.push(cartItems.indexOf(i));
}
});
for (let i = idIndexes.length - 1; i >= 0; i--) {
cartItems.splice(idIndexes[i], 1);
}
});
i.addEventListener('mouseup', () => {
if (dropdownCheckoutContainer.childElementCount <= 2) {
document.getElementById('empty-cart').style.display = 'block';
checkoutLink.classList.add('checkout-link-disabled');
}
if (dropdownCheckoutContainer.childElementCount <= 2) {
notificationIconContainer.style.display = 'none';
}
});
}
console.log(cart);
});
i.addEventListener('mouseup', () => {
document.getElementById('empty-cart').style.display = 'none';
checkoutLink.removeAttribute('class', 'checkout-link-disabled');
});
});
suppose, You have a data like that
let cart = { 'cart-items': [{id: 1, name: 'test 1', price: 30.9, quantity: 1}] }
When You are going to click on button then currentCardId = 1
Then you need to the following at click event.
const existsIndex = cart['cart-items'].findIndex((item) => item.id === currentCardId )
if (existsIndex !== -1) {
cart['cart-items'][existsIndex].quantity++
} else {
cart['cart-items'].push({id: currentCardId, name: 'sadsad', quantity: 1})
}

Orchard CMS default Pager issues

The scenario is this:
There are 13 items in a projection in total. In default Orchard displays 2 pages (10 on the 1st, 3 on the 2nd page). If the user is on the 2nd page then chooses the option to show 50, then Orchard leaves the ?page=2 in the url and it messes the pager up. Showing 51-13 of 13 items. A bug report has been filled with the community behind Orchard, but I though someone could help with this, as it's a small code snippet. I guess the Javascript at the end needs to be modified, but I'm not really sure...
The pager.cshtml (copied from AdminView):
#{
Model.PreviousText = T("<");
Model.NextText = T(">");
var routeData = new RouteValueDictionary(ViewContext.RouteData.Values);
var queryString = ViewContext.HttpContext.Request.QueryString;
if (queryString != null) {
foreach (string key in queryString.Keys) {
if (key != null && !routeData.ContainsKey(key)) {
var value = queryString[key];
routeData[key] = queryString[key];
}
}
}
if (routeData.ContainsKey("id") && !HasText(routeData["id"])) {
routeData.Remove("id");
}
var totalPageCount = (int)Math.Ceiling((double)Model.TotalItemCount / Model.PageSize);
Model.Metadata.Type = "Pager_Links";
IHtmlString pagerLinks = Display(Model);
Model.Classes.Add("selector");
var pageSizeTag = Tag(Model, "ul");
if (Model.RouteData != null) {
foreach (var rd in Model.RouteData.Values) {
routeData[rd.Key] = rd.Value;
}
}
var pageSizes = new List<int?> { 10, 50, 100 };
var defaultPageSize = WorkContext.CurrentSite.PageSize;
if (!pageSizes.Contains(defaultPageSize)) {
pageSizes.Add(defaultPageSize);
}
Script.Require("jQuery");
}
#if (Model.TotalItemCount > 1) {
<div class="pager-footer">
<span class="page-results">#T("Showing {0} - {1} of {2} jobs", (Model.Page - 1) * (int)Model.PageSize + 1, Model.PageSize == 0 ? Model.TotalItemCount : Math.Min(Model.TotalItemCount, (Model.Page) * (int)Model.PageSize), Model.TotalItemCount)</span>
#if (totalPageCount > 1 || Model.PageSize == 0 || Model.PageSize > pageSizes.First()) {
<div class="page-size-options group">
#T("Show:") #pageSizeTag.StartElement
#{ routeData["pageSize"] = 0; }
#if ((int)Model.PageSize == 0) {
<li class="selected"><span>#T("All").ToString()</span></li>
} else {
<li>#Display.ActionLink(Value: T("All"), Action: (string)routeData["action"], Controller: (string)routeData["controller"], RouteValues: routeData)</li>
}
#foreach (int size in pageSizes.OrderBy(p => p)) {
routeData["pageSize"] = size;
if ((int)Model.PageSize == size) {
<li class="selected"><span>#size.ToString()</span></li>
} else {
<li>#Display.ActionLink(Value: size, Action: (string)routeData["action"], Controller: (string)routeData["controller"], RouteValues: routeData)</li>
}
}
#pageSizeTag.EndElement
</div>
}
#if (totalPageCount > 1 || Model.PageSize != 0) {
#pagerLinks
}
</div>
}
#using (Script.Foot()) {
<script type="text/javascript">
//<![CDATA[
$(function () {
$('ul.selector').each(function () {
var self = $(this),
options = $.map(self.find("li"), function (li) {
var self = $(li);
return $("<option/>", {
value: self.children("a").attr("href"),
text: self.text(),
selected: self.hasClass("selected")
})[0];
}),
select = $("<select/>", {
id: self.attr("id") + "Selector",
"class": self.attr("class"),
name: self.attr("name") + "Selector"
}).change(onSelectChange).append(options);
self.replaceWith(select);
});
function onSelectChange() {
// redirect to page with new page size
// disable button so that no other value can be chosen while the form is submited
window.location = $(this).attr("disabled", true).val();
}
})
//]]>
</script>
}
I've found the fix on codeplex
I'll give it a try.

Illustrator JavaScript only works once - won't toggle

I'm writing a script which changes the colours of a stick-man's arms and legs. Once "he" is selected, it effectively just mirrors the colours:
//Declare and initialize variables
var msgType = "";
var app;
var docRef = app.activeDocument;
var testColor = docRef.swatches.getByName("CMYK Green");
var leftColor = docRef.swatches.getByName("LeftColor");
var rightColor = docRef.swatches.getByName("RightColor");
function sameColor(CMYKColor1, CMYKColor2) {
"use strict";
var isTheSameColor;
if ((CMYKColor1.cyan === CMYKColor2.cyan) && (CMYKColor1.magenta === CMYKColor2.magenta) && (CMYKColor1.yellow === CMYKColor2.yellow) && (CMYKColor1.black === CMYKColor2.black)) {
isTheSameColor = true;
} else {
isTheSameColor = false;
}
return isTheSameColor;
}
// check if a document is open in Illustrator.
if (app.documents.length > 0) {
var mySelection = app.activeDocument.selection;
var index;
// Loop through all selected objects
for (index = 0; index < mySelection.length; index += 1) {
// Switch left and right colours
if (sameColor(mySelection[index].strokeColor, leftColor.color)) {
mySelection[index].strokeColor = rightColor.color;
}
if (sameColor(mySelection[index].strokeColor, rightColor.color)) {
mySelection[index].strokeColor = leftColor.color;
}
if (sameColor(mySelection[index].fillColor, leftColor.color)) {
mySelection[index].fillColor = rightColor.color;
}
if (sameColor(mySelection[index].fillColor, rightColor.color)) {
mySelection[index].fillColor = leftColor.color;
}
}
}
It works, but it only works once (i.e. I can't toggle the change again). If I undo the change and try again it works again. Why is this?
After a lot of head-scratching / debugging it turns out that it was changing the CMYK values to be not quite the same (by a tiny fraction).
Changed the following:
if ((CMYKColor1.cyan === CMYKColor2.cyan) ...
to:
if ((Math.round(CMYKColor1.cyan) === Math.round(CMYKColor2.cyan)) ...
and it works fine now.

Categories