Get highest values from objects created with map - javascript

I have dynamically added divs with nested divs to the dom. These have data-attributes:
data-name-nr, data-model, data-price.
What I want is to take the highest value of "data-price" to an array from each of all "data-div". In my example there is two nested divs inside the last
More explanation: In my example I have three div with class "frame" = I need an array with three values. In reality there night be whatever between 1 and 10 or even more.
So the outcome of my example would be
let array = [100,150,200]
or
let object = {1:100,2:150,3:200} //from the name-nr
So far I only managed to map the data-items
I tried with map.get and other, they all gave me errors and I don't know which direction I should go. Please can you help?
Example:
HTML
<div class="flex">
<div class="frame" data-name-nr="1">
<div class="border" data-name-nr="1" data-price="100" data-div="1/1"></div>
</div>
<div class="frame" data-name-nr="2">
<div class="border" data-name-nr="2" data-price="150" data-div="1/1"></div>
</div>
<div class="frame" data-name-nr="3">
<div class="border fifty" data-name-nr="3" data-price="100" data-div="1/2"></div>
<div class="border fifty" data-name-nr="3" data-price="200" data-div="2/2"></div>
</div>
</div>
JS
function functionName() {
jQuery( ".frame .box" ).map(function() {
const key = ['name','model','price']
let values = [[jQuery(this).data("name-nr"),( jQuery(this).data('div')),( jQuery(this).data('price'))]]
let result = values.map(row =>
row.reduce((acc, cur, i) =>
(acc[key[i]] = cur, acc), {}))
console.log(result[0])
})
}
$(document).on('click', '.click', functionName)
Console
Object { name: 1, model: "1/1", price: 100 }
Object { name: 2, model: "1/1", price: 150 }
Object { name: 3, model: "1/2", price: 100 }
Object { name: 3, model: "2/2", price: 200 }
https://jsfiddle.net/mik_a/a6jt7kb0/

Create a hash table by reducing to a hash with unique names with the largest price and then take them out to the array as required.
See demo below:
function functionName() {
let hash = jQuery(".frame .box").map(function() {
return {
name: jQuery(this).data("name-nr"),
model: jQuery(this).data('div'),
price: jQuery(this).data('price')
};
}).get().reduce(function(p,c){
if((p[c.name] && p[c.name].price < c.price) || !p[c.name])
p[c.name] = c
return p;
},Object.create(null));
let result = Object.keys(hash).map(function(e) {
return hash[e];
});
console.log(result);
}
$(document).on('click', '.click', functionName)
.flex {
display: flex;
align-items: center;
justify-content: center;
width: 400px;
height: 300px;
}
.frame {
outline: 1px solid red;
flex: 1;
display: flex;
flex-direction: column;
height: 100%;
}
.box {
border-top: 1px solid green;
}
.fifty {
height: 50%;
}
button {
width: 100px;
height: 35px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="flex">
<div class="frame" data-name-nr="1">
<div class="box" data-name-nr="1" data-price="100" data-div="1/1"></div>
</div>
<div class="frame" data-name-nr="2">
<div class="box" data-name-nr="2" data-price="150" data-div="1/1"></div>
</div>
<div class="frame" data-name-nr="3">
<div class="box fifty" data-name-nr="3" data-price="100" data-div="1/2"></div>
<div class="box fifty" data-name-nr="3" data-price="200" data-div="2/2"></div>
</div>
</div>
<button class="click" value="CLICK">
click
</button>
and the ES6 version:
function functionName() {
let hash = jQuery(".frame .box").map(function() {
return {
name: jQuery(this).data("name-nr"),
model: jQuery(this).data('div'),
price: jQuery(this).data('price')
};
}).get().reduce((p, c) => {
if ((p[c.name] && p[c.name].price < c.price) || !p[c.name])
p[c.name] = c;
return p;
}, Object.create(null));
let result = Object.keys(hash).map(e => hash[e]);
let sum = Object.keys(hash).map(e => hash[e].price).reduce((p,c) => p + c, 0);
console.log(result, sum);
}
$(document).on('click', '.click', functionName)
.flex{display:flex;align-items:center;justify-content:center;width:400px;height:300px}.frame{outline:1px solid red;flex:1;display:flex;flex-direction:column;height:100%}.box{border-top:1px solid green}.fifty{height:50%}button{width:100px;height:35px}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="flex">
<div class="frame" data-name-nr="1">
<div class="box" data-name-nr="1" data-price="100" data-div="1/1"></div>
</div>
<div class="frame" data-name-nr="2">
<div class="box" data-name-nr="2" data-price="150" data-div="1/1"></div>
</div>
<div class="frame" data-name-nr="3">
<div class="box fifty" data-name-nr="3" data-price="100" data-div="1/2"></div>
<div class="box fifty" data-name-nr="3" data-price="200" data-div="2/2"></div>
</div>
</div>
<button class="click" value="CLICK">
click
</button>

You could select the frame and then reduce on the inside boxes:
$('.frame').map(function() {
const biggerBox = $(this).find('.box').toArray().reduce((bigger, current) =>
$(bigger).data('price') > $(current).data('price') ? bigger : current)
const data = $(biggerBox).data()
console.log({ name: data.nameNr, price: data.price, div: data.div })
})
using a fork from your fiddle: https://jsfiddle.net/zmq5jdh5/

Related

Modal Window on card click JS CSS PHP

So I have 6 cards on my html. Each one on click need to pop up a modal window (this modal window is the card with more informations, so each modal window is corresponding to one card).
I dont know how to do that. After a day searching on the web I'm here to ask your help.
I have tried to make the html animal_card, and my modal appart. Then all the content will change with php.
And the Javascript need to change the modal window css property to absolute on click.
Someone know how to do that with Javascript ?
HTML :
<div class="animal_card">
<div class="card_title">
<h3>title</h3>
</div>
<div class="card_image">
<img src="image.img" alt="">
</div>
<div class="card_text">
<div class="card_info">
<div class="card_info_age">
<h4>Age</h4>
<p>14</p>
</div>
<div class="card_info_gender">
<h4>Gender :</h4>
<p>Female</p>
</div>
</div>
<h4>Who am I</h4>
<p>Description Text</p>
</div>
</div>
<div class="bg-modal">
<div class="modal-content">
<div class="modal-animal">
<h1>Animal Name</h1>
<button class="close" onclick="closeModal()">&times</button>
<div><img src="img/greciaprofile.jpg" alt=""></div>
<div class="animal-informations">
<div class="left">
<label for="">Age</label>
<p>14</p>
<label for="">Sexe</label>
<p>Female</p>
</div>
<div class="right">
<label for="">Description</label>
<p>
Text
</p>
</div>
</div>
<div>
<button class="main">Adopt</button>
<button class="secondary">Support</button>
</div>
</div>
</div>
</div>
CSS :
.bg-modal {
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.7);
position: absolute;
top: 0;
left: 0;
display: flex;
justify-content: center;
}
.modal-content {
position: absolute;
margin-top: 5rem;
width: 75vw;
background-color: $white;
border-radius: 15px;
}
Javascript :
const cards = document.querySelectorAll('.animal_card');
const modal = document.getElementsByClassName('bg-modal');
const onCardClick = async (e) => {
const card = e.currentTarget;
modal.style.position = 'absolute';
}
cards.forEach(card => card.addEventListener('click', onCardClick));
function closeModal() {
modal[0].style.position = 'none';
}
const cards = document.querySelectorAll('.animal_card');
const modal = document.getElementsByClassName('bg-modal');
const getKeyMap = (modal) => {
if (modal) {
let i;
let keyMap = {};
for (i = 0; i < modal.length; i++) {
const item = modal[i];
const key = item.getAttribute('key');
keyMap[key] = item;
}
return keyMap;
}
return null;
};
const modalMap = getKeyMap(modal);
const onCardClick = async (e) => {
const card = e.currentTarget && e.currentTarget.getAttribute('key') || null;
const selectedModal = modalMap[card] || null;
if (selectedModal) {
selectedModal.style.position = 'absolute';
}
}
cards.forEach(card => card.addEventListener('click', onCardClick));
.bg-modal {
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.7);
/* position: absolute; */
top: 0;
left: 0;
display: flex;
justify-content: center;
}
.modal-content {
position: absolute;
margin-top: 5rem;
width: 75vw;
background-color: $white;
border-radius: 15px;
}
<div key="5" class="animal_card">
<div class="card_title">
<h3>title</h3>
</div>
<div class="card_image">
<img src="image.img" alt="">
</div>
<div class="card_text">
<div class="card_info">
<div class="card_info_age">
<h4>Age</h4>
<p>14</p>
</div>
<div class="card_info_gender">
<h4>Gender :</h4>
<p>Female</p>
</div>
</div>
<h4>Who am I</h4>
<p>Description Text</p>
</div>
</div>
<div class="bg-modal" key="5">
<div class="modal-content">
<div class="modal-animal">
<h1>Animal Name</h1>
<button class="close">&times</button>
<div><img src="img/greciaprofile.jpg" alt=""></div>
<div class="animal-informations">
<div class="left">
<label for="">Age</label>
<p>14</p>
<label for="">Sexe</label>
<p>Female</p>
</div>
<div class="right">
<label for="">Description</label>
<p>
Text
</p>
</div>
</div>
<div>
<button class="main">Adopt</button>
<button class="secondary">Support</button>
</div>
</div>
</div>
</div>
So the direct answer using your example is modal on the onCardClick is returning a collection, not a single element. So selecting the first one modal[0] will fix the position update. I attached an example.
If you are going to show different modals based on the card you click on, you generally need to have a method to track them. Really depends on how you want to do that, based on ids, or index position or so on. Anyways, let me know if this helps.

jQuery - Display text when hovered on through `for` loop

I am making a webpage and I am adding a feature; when you hover on a certain div another div will display a certain text. There are 5 elements I want to be able to hover and display text.
I added this feature but it did not work properly - only the last hoverable div displayed the text. I isolated the elements used and moved them to a sandbox to tweak them. No matter what I do (I got it to work by using a bunch of if statements, but I am trying to remove that so it looks neater), only the last div will display the text.
Here is a fiddle of the working version with the many if statements:
https://codepen.io/SynergyOfLife/pen/qBNJboR
setInterval(function(){
var dataArray = ["1","2","3","4","5"]
var isHovered1 = $(`.${dataArray[0]}`).is(":hover");
var isHovered2 = $(`.${dataArray[1]}`).is(":hover");
var isHovered3 = $(`.${dataArray[2]}`).is(":hover");
var isHovered4 = $(`.${dataArray[3]}`).is(":hover");
var isHovered5 = $(`.${dataArray[4]}`).is(":hover");
if (isHovered1) {
$('p').html("TEST")
} else if (isHovered2) {
$('p').html("TEST")
}else if (isHovered3) {
$('p').html("TEST")
} else if (isHovered4) {
$('p').html("TEST")
}else if (isHovered5) {
$('p').html("TEST")
} else {
$('p').html("")
}
}, 300);
div {
height:100px;
width: 100px;
background: blue;
float: left;
}
.viewer {
height: 500px;
width: 500px;
background: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="1">
<a>Test</a>
</div>
<div class="2">
<a>Test</a>
</div>
<div class="3">
<a>Test</a>
</div>
<div class="4">
<a>Test</a>
</div>
<div class="5">
<a>Test</a>
</div>
<div class="viewer">
<p></p>
</div>
Here is the version I am trying to perfect:
https://codepen.io/SynergyOfLife/pen/VwjELME
setInterval(function(){
var dataArray = ["1","2","3","4","5"]
var i;
for (i = 0; i < dataArray.length; i++) {
var isHovered = $(`.${dataArray[i]}`).is(":hover");
if (isHovered) {
$('p').html("TEST")
} else {
$('p').html("")
}
}
}, 300);
div {
height:100px;
width: 100px;
background: blue;
float: left;
}
.viewer {
height: 500px;
width: 500px;
background: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="1">
<a>Test</a>
</div>
<div class="2">
<a>Test</a>
</div>
<div class="3">
<a>Test</a>
</div>
<div class="4">
<a>Test</a>
</div>
<div class="5">
<a>Only working div?</a>
</div>
<div class="viewer">
<p></p>
</div>
In summary, I am asking for help on how to shorten the number of if statements
Just use the hover() method which accepts two functions, one for mouseenter and one for mouseleave.
var dataArray = ["1", "2", "3", "4", "5"]
var selectors = '.' + dataArray.join(',.');
$(selectors).hover(function() {
// `this` is the element the event occurred on
$('p').html('TEST ' + this.className)
}, function() {
$('p').empty()
})
div {
height: 100px;
width: 100px;
background: blue;
float: left;
}
.viewer {
height: 500px;
width: 500px;
background: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="1">
<a>Test</a>
</div>
<div class="2">
<a>Test</a>
</div>
<div class="3">
<a>Test</a>
</div>
<div class="4">
<a>Test</a>
</div>
<div class="5">
<a>Test</a>
</div>
<div class="viewer">
<p></p>
</div>

how should I get access to DOM elements and also wants loop and add X or O on the board

I just want to Add X or O on the board whenever a user clicks at any cell on the board.
Class cell's X and item's X are for just experiment.
By placeMark function X or O will be marked in the board
let x = 'X'
let o = 'O'
let xTurn = true
const board = document.getElementById("board")
const cell = document.getElementsByClassName("cell")
cell.forEach(cell => {
cell.classList.remove(x)
cell.classList.remove(o)
cell.removeEventListener('click', handleClick)
cell.addEventListener('click', handleClick, {
once: true
})
})
function handleClick(e) {
const cell = e.target
const currentClass = xTurn ? x : o
placeMark(cell, currentClass)
}
function placeMark(cell, currentClass) {
cell.classList.add(currentClass)
}
<div class="board" id="board">
<div class="cell x" id="item 1"></div>
<div class="cell" id="item 2"></div>
<div class="cell" id="item 3"></div>
<div class="cell" id="item 4"></div>
<div class="cell" id="item 5"></div>
<div class="cell" id="item 6"></div>
<div class="cell" id="item 7"></div>
<div class="cell" id="item 8"></div>
<div class="cell" id="item 9"></div>
</div>
edited!!
I am using VS Code.
As #GMCgit mentioned, your IDs are not unique. You are not allowed to use space in the id attribute, so this has to be changed to id="item-1" or something similar.
Also, cell in your case is an HTMLCollection. .forEach is a method used for arrays. If you want to store your cells in array, better use .querySelectorAll('.cell').
Also, you are not switching xTurn anywhere. Please note that your X and O are capitalized, so you have to use uppercase "X" and "O" in your CSS.
I have added a working example with a little bit of CSS just to show the effect.
let x = 'X'
let o = 'O'
let xTurn = true
const board = document.getElementById("board")
const cells = document.querySelectorAll(".cell")
cells.forEach(cell => {
cell.classList.remove(x, o)
cell.addEventListener('click', handleClick, {
once: true
})
})
function handleClick(e) {
const cell = e.target;
const currentClass = xTurn ? x : o;
placeMark(cell, currentClass);
xTurn = !xTurn;
}
function placeMark(cell, currentClass) {
cell.classList.add(currentClass)
}
.board {
display: flex;
flex-wrap: wrap;
width: 306px;
}
.cell {
position: relative;
width: 100px;
height: 100px;
border: 1px solid #000;
}
.cell:after {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 20px;
}
.cell.X:after {
content: 'X';
}
.cell.O:after {
content: 'O';
}
<div class="board" id="board">
<div class="cell" id="item-1"></div>
<div class="cell" id="item-2"></div>
<div class="cell" id="item-3"></div>
<div class="cell" id="item-4"></div>
<div class="cell" id="item-5"></div>
<div class="cell" id="item-6"></div>
<div class="cell" id="item-7"></div>
<div class="cell" id="item-8"></div>
<div class="cell" id="item-9"></div>
</div>
I have deleted unnecessary code so the demo to work.
Firstly your ids repeat which is not really good and you can use:
const cell = document.getElementsByClassName("cell");

Displaying multiple objects one at a time in a dialog box

I am completely stuck. I am trying to display objects individually in a pop-up dialog box, and I can't find any information as to how to do this. I can display them all at once, but that is not what I am trying to do.
$.each(needs, function(i, v) {
console.info(v);
var brand = v.brand;
console.info(brand);
var model = v.model;
var growerID = v.growerID;
if (v.portalID === null) {
var unmatched = {
brand: v.brand,
model: v.model,
growerID: v.growerID
}
newmatch.push(unmatched);
console.info(newmatch);
} else {
return false;
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="wrap">
<form>
<div class="fleft">
<div>
<img src="/app/public/css/images/logo.png">
</div>
<div class="form-group brand ui-corner-all">
<label for="owner">Brand</label>
<div class="card-type ui-corner-all " id="brand"></div>
</div>
<div class="form-group ui-corner-all">
<label for="model">Model</label>
<div class="model ui-corner-all " id="trxio_model"></div>
</div>
<div class="form-group growerId">
<label for="growerId">Grower ID</label>
<div class="card-type ui-corner-all " id="growerId"></div>
</div>
<div class="form-group vendor ui-corner-all ">
<label for="owner">Default Vendor</label>
<div class="card-type ui-corner-all " id="vendor"></div>
</div>
<button type="submit" class="btn btn-lg">Update Product Info</button>
</div>
</form>
</div>
Any help would be appreciated. Thanks.
Because you provided only a partial code that doesn't really work I've written a little example how to iterate over a collection of cars and how to render them into HTML container. Hopefully that will lead you to the solution:
var cars = [
{
name: "VW",
year: 1988,
},
{
name: "Honda",
year: 1999,
},
{
name: "BMW",
year: 2005,
}
]
const container = document.querySelector('#container')
const toRender = cars.map(car => `<div class="car"><span class="name">${car.name}</span> <span class="year">${car.year}</span></div>`)
container.innerHTML = toRender.join('')
.container {
padding: 10;
background: #f0f0f0;
}
.car {
margin: 10px 0;
}
.name {
display: inline-block;
padding: 5px;
color: #ff0000;
min-width: 100px;
}
.year {
color: blue;
}
<div id="container"></div>

Limit count of elements in div

I have div with questions
Here is it
Here is code for it
<div class="listdivright">
<div style="height: 80%; width: 100%; overflow: auto">
#foreach (var item in Model)
{
<div class="title" style="margin-top:15px;margin-left:15px; margin-bottom: 10px;">
<img class="click" src="#Url.Content("~/Images/plus_plus.png")" />
<span>
#Html.TextBoxFor(modelItem => item.question, new {#class="testclass", #readonly = "readonly" })
</span>
<a class="click2" style="margin-left:10px;">
<img src='#Url.Content("~/Images/arrow.png")' />
</a>
<a style="margin-left:25px;" href='#Url.Action("Edit", "Questions", new {id = item.QuestionId})'>
<img src='#Url.Content("~/Images/Edit.png")' />
</a>
<a href='#Url.Action("Delete", "Questions", new {id = item.QuestionId})'>
<img src='#Url.Content("~/Images/Delete.png")' />
</a>
</div>
<div class="content" style="margin-left:60px; width: 80%; height: 100px; background: white">
<div style="width: 100%">
<div style="float:left; width: 50%;">
<b>#Html.LabelFor(modelItem=>item.TimeForAnswer)</b>
<b>:</b>
<span>#Html.DisplayFor(modelItem=>item.TimeForAnswer)</span>
</div>
<div style="float:right;width: 50%;">
<b>#Html.LabelFor(modelItem => item.TimeForReady)</b>
<b>:</b>
<b>#Html.DisplayFor(modelItem => item.TimeForReady)</b>
</div>
</div>
<div style="width: 100%; text-align: center;" >
<b>#Html.LabelFor(modelItem => item.Retries)</b>
<b>:</b>
<b>#Html.DisplayFor(modelItem => item.Retries)</b>
</div>
</div>
}
</div>
I use JS to move block to left div
Code of JS script
<script type="text/javascript" >
$('.title').on('click', function () {
$(this).next().toggle();
});
$('.click2').click(function () {
var elem = $(this).closest('.title');
$('.title2').append($(elem).html()).show();
});
Here is code of left div
<div class="listdivleft">
<div style="height: 80%; width: 100%; overflow: auto">
<div class="title2" style="margin-top: 15px; margin-left: 15px; margin-bottom: 15px;padding-top: 10px">
</div>
</div>
</div>
I need to limit blocks in left div. From 0 to 10.
So it can be 0 or not more than 10
How I can do this?
You can check that if element with class title are less than 10 using length property, in that case only the new html should be appended, something like:
if($(".title").length < 10) {
var elem = $(this).closest('.title');
$('.title2').append($(elem).html()).show();
}
else {
alert("No more than 10 allowed.");
}
or if title class is reused other places as well on page, then restrict it to current parent element using listdivright class element in combination with closest and find :
if($(this).closest(".listdivright").find(".title").length < 10) {
var elem = $(this).closest('.title');
$('.title2').append($(elem).html()).show();
}
else {
alert("No more than 10 allowed.");
}
Hope it helps and gives you idea how it can be done.

Categories

Resources