How to style a singular v-for item in vue, based on a condition? - javascript

I am making a multiple choice quiz game and want what the user clicked to change to either red or green depending on if that answer is correct or incorrect. I made a variable called selected which is what the user pressed- this does correctly update. I have also got all of the v-for items to change to the same colour depending on if the answer is correct or not, I only need help separating it so that only one of the v-for things change colour.
Here is my relative HTML:
<button type="button" class="btn" class="answer" v-for="option in options" #click="checkAnswer(option)" #click="selected = option" :style="{backgroundColor: colour}">
{{option}}<br/>
</button>
<button type="button" #click="getQ" #click="shuffle(options)" class="btn button next">Next</button>
Here is the relative JS:
let colour = Vue.ref('');
let selected = Vue.ref('');
let options = Vue.ref([correctAnswer, incorrectAnswerOne, incorrectAnswerTwo, incorrectAnswerThree]);
// Methods
let shuffle = function(options) {
let num = options.length, t, raInt;
//while there are remaining elements to shuffle
while (num) {
//choose random
raInt = Math.floor(Math.random() * num--);
//swap with current element
t = options[num];
options[num] = options[raInt];
options[raInt] = t;
}
return options;
};
let checkAnswer = function(clicked) {
console.log(clicked.value);
console.log(correctAnswer.value);
if (clicked.value == correctAnswer.value) { // checks if the button that was clicked is the same as the answers value
this.result = "Correct!"; //if it does, result changes to Correct!
this.colour = "green";
} else {
this.result = "Incorrect!"; //if the answer is incorrect, result changes to Incorrect!
this.colour = "red";
};
};
And here is some CSS:
.answer {
width: 100%;
background-color: #dbdbdb;
padding: 4% 2%;
margin: 1 0;
}
.answer:hover {
background-color: #c2c2c2
}
I haven’t really tried that much. I’m not sure what to try. In a different project I did style a different div based on what other div was selected, but I am not sure how to change just one part of a v-for, or if it is even possible.
Thanks in advance

You can set condition for showing color style:
const { ref, computed } = Vue
const app = Vue.createApp({
setup() {
let correctAnswer = 3
let incorrectAnswerOne = 1
let incorrectAnswerTwo = 2
let incorrectAnswerThree = 4
let colour = ref('');
let selected = ref('');
let options = ref([correctAnswer, incorrectAnswerOne, incorrectAnswerTwo, incorrectAnswerThree]);
let shuffled = ref([])
let shuffle = (array) => {
selected.value = null
let currentIndex = array.length, randomIndex;
while (currentIndex != 0) {
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex--;
[array[currentIndex], array[randomIndex]] = [
array[randomIndex], array[currentIndex]];
}
shuffled.value = array;
};
shuffle(options.value)
let checkAnswer = function(clicked) {
// 👇 set selected
selected.value = clicked
if (clicked == correctAnswer) {
this.result = "Correct!";
this.colour = "green";
} else {
this.result = "Incorrect!";
this.colour = "red";
};
};
return { colour, selected, options, shuffle, checkAnswer, shuffled }
},
})
app.mount('#demo')
.answer {
width: 100%;
background-color: #dbdbdb;
padding: .5em 2em;
margin: 1 0;
}
.answer:hover {
background-color: #c2c2c2
}
.btns {
display: flex;
}
<script src="https://unpkg.com/vue#3/dist/vue.global.prod.js"></script>
<div id="demo">
<div class="btns">
<div v-for="(option, i) in shuffled" :key="i" >
<!-- 👇 condition -->
<button class="answer" #click="checkAnswer(option)" :style="selected == option && {backgroundColor: colour}">
{{option}}<br/>
</button>
</div>
</div>
<button type="button" #click="getQ, shuffle(options)" class="btn button next">Next</button>
</div>

Related

Cannot implement shuffle bars feature in sorting algorithm visualizer - setTimeout updates are not rendering

I'm making a sorting algorithm visualizer project and I'm in the process of implementing a shuffle button. The visualization involves bars of different heights getting moved around. I would like the shuffle button to modify the bar array one step at a time, showcasing each swap at a high speed. I've tried tweaking many different things (some of which do move bars around in a strange manner), but I can't seem to get the desired functionality to work. Here's some of the relevant code:
// Swap does not modify the original array, but the implementation details don't really affect the result.
// It basically swaps two elements in the bar array, and then returns the updated array.
const swapBars = (bars, bar1, bar2) => {
if (!bars || !bar1 || !bar2) {
return;
}
const _bars = bars;
let _bar1 = bar1;
let _bar2 = bar2;
const tempLeft = _bar1.left;
_bar1.left = _bar2.left;
_bar2.left = tempLeft;
const temp = _bar1;
_bar1 = _bar2;
_bar2 = temp;
return _bars;
};
// Init bars is basically synchronous shuffle. It takes the array that is created and shuffles it
// because the array should begin in a shuffled state. This is working properly.
const initBars = (bars) => {
let currentIndex = bars.length - 1;
while (currentIndex > 0) {
// randomIndex will always be different from currentIndex, so each bar will always shuffle
const randomIndex = Math.floor(Math.random() * currentIndex);
swapBars(bars, bars[currentIndex], bars[randomIndex]);
currentIndex--;
}
setBarsToRender(bars);
};
// createBarArray is what is used to actually populate an empty array with bars depending on a number passed
// through by a slider. This is also working properly.
const createBarArray = (quantity) => {
let bars = [];
const width = calcWidthPercentage(quantity);
for (let i = 0; i < quantity; i++) {
const height = calcHeightPercentage(quantity, i + 1);
const left = calcLeftPosPercentage(quantity, i + 1);
bars.push({ correctPos: i, height: height, width: width, left: left });
}
return initBars(bars);
};
// shuffleBars seems to be broken. I've tried many different things, and this is just the latest snapshot of it.
// It is being called when the shuffle button is being clicked using `shuffleBars(barsToRender)` where barsToRender is the stateful value that is being rendered.
const shuffleBars = (bars) => {
let currentIndex = bars.length - 1;
while (currentIndex > 0) {
const randomIndex = Math.floor(Math.random() * currentIndex);
setTimeout(() => {
setBarsToRender((prev) => {
return swapBars(prev, prev[currentIndex], prev[randomIndex]);
});
}, 50 * (bars.length - currentIndex));
currentIndex--;
}
};
If I do something like moving the swapBars call inside setBarsToRender outside of it and then
do setBarsToRender[...bars], I can see some of the bars moving, but not with the intended behavior (the smallest bar is the only one that keeps swapping). I'm not sure if I'm misunderstanding how state updates work inside setTimeout, or if it's something else, so I'd greatly appreciate some help.
I removed the setTimeout and used a transition delay to create the staggered effect.
Working demo below:
const swapBars = (bars, bar1, bar2) => {
if (!bars || !bar1 || !bar2) {
return;
}
const _bars = bars;
let _bar1 = bar1;
let _bar2 = bar2;
const tempLeft = _bar1.left;
_bar1.left = _bar2.left;
_bar2.left = tempLeft;
const temp = _bar1;
_bar1 = _bar2;
_bar2 = temp;
return _bars;
};
const initBars = (bars) => {
let currentIndex = bars.length - 1;
while (currentIndex > 0) {
const randomIndex = Math.floor(Math.random() * currentIndex);
swapBars(bars, bars[currentIndex], bars[randomIndex]);
currentIndex--;
}
return bars;
};
const createBarArray = (quantity) => {
let bars = [];
const width = 100 / quantity;
for (let i = 0; i < quantity; i++) {
const height = width * (i + 1);
const left = width * i;
bars.push({ correctPos: i, height: height, width: width, left: left });
}
return initBars(bars);
};
function Bars({ quantity = 10 }) {
const [barsToRender, setBarsToRender] = React.useState([]);
React.useEffect(() => {
const bars = createBarArray(quantity);
setBarsToRender(bars);
}, [quantity]);
const shuffleBars = () => {
const bars = [...barsToRender];
setBarsToRender(initBars(bars));
};
return (
<div>
<ul
style={{
height: "50vh",
display: "flex",
position: "relative"
}}
>
{barsToRender.map((bar, i) => (
<Bar key={bar.correctPos} bar={bar} index={i} />
))}
</ul>
<button onClick={shuffleBars}>Shuffle</button>
</div>
);
}
function Bar({ bar, index: i }) {
return (
<li
style={{
background: "blue",
height: `${bar.height}%`,
width: `${bar.width}%`,
left: `${bar.left}%`,
position: "absolute",
bottom: 0,
transitionProperty: "left",
transitionTimingFunction: "ease-in-out",
transitionDuration: ".25s",
transitionDelay: `${i*50}ms`
}}
>
<p>{bar.correctPos}</p>
</li>
);
}
ReactDOM.createRoot(document.getElementById("root")).render(<Bars />)
p {
font-family: sans-serif;
font-weight: 700;
height: 1.5rem;
width: 1.5rem;
display: grid;
place-content: center;
background: white;
border-radius: 50%;
border: 1px solid;
}
ul {
padding: 0;
list-style-type: none;
}
li {
display: grid;
align-content: end;
justify-items: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.development.js"></script>
<div id="root"></div>

progressbar html tag change

I'am working on progressbar that change the level when reaching some point.
The code.
I want to change the text under the progressbar when the progressbar reach 100 or above 90.
I could change it once but I want to go to next level, like this.
silver ==> gold ==> diamond ==> and more
const step = 5;
var content=document.getElementById('mylevel').innerHTML;
const updateProgress = () => {
const currentWidth = Number(document.getElementById("progressvalue").style.width.replace( "%", ""));
if (currentWidth>=100) {
return;
}
else {
document.getElementById("progressvalue").style.width = `${currentWidth+step}%`;
}
if (currentWidth > 90) {
document.getElementById("mylevel").textContent = "gold";
document.getElementById("progressvalue").style.width = "0%";
}
if (currentWidth > 90 && content == "gold") {
document.getElementById("mylevel").textContent = "diamond";
document.getElementById("progressvalue").style.width = "0%";
}
}
const restart = () => {
document.getElementById("progressvalue").style.width = "0%";
}
.progress {
background-color: #ededed;
width: 100%;
overflow: hidden;
}
#progressvalue {
height: 40px;
background-color: lightgreen;
width: 0%;
}
<div class="progress">
<div id="progressvalue"></div>
</div>
<p id="mylevel">silver</p>
<br />
<button type="button" onclick="updateProgress()">
Update Progress
</button>
<button type="button" onclick="restart()">
Restart
</button>
When the updateprogress is above 90 the silver change to gold, but I need to change again to diamond when the updateprogress is again above 90.
Am I putting the if condition in a wrong place, I tried many times.
I don't know what I'am missing and am new with JavaScript
I started the code but got help here to make it much better (80% of the code done by
teresaPap thanks)
Update
After closer inspection it is an issue of content not updating you need to put it inside updateProgress() or it will forever remain the initial value.
const step = 5;
const updateProgress = () => {
var content = document.getElementById('mylevel').innerHTML;
//the rest of the code
I do however recommend you to improve your if statements. You only need one if for this task.
A better solution
A better solution would be something like this:
Add a hidden value to keep your level progress
</div>
<p id="hiddenlevel">0</p>
<p id="mylevel">silver</p>
<br />
and css:
#hiddenlevel {
height: 0px;
visibility: hidden;
width: 0%;
}
now that you have a hidden value you can wrap up all future ifs in a single one.
const levels = ["silver", "gold", "diamond"]
var mylevel = Number(document.getElementById("hiddenlevel").innerHTML);
if(currentWidth > 90 && mylevel < levels.length){
document.getElementById("hiddenlevel").textContent = mylevel + 1;
document.getElementById("mylevel").textContent = levels[mylevel + 1];
document.getElementById("progressvalue").style.width = "0%";
}
and just like that you can just add a new level inside the levels array and it will be added without issues.
Update 2
Just noticed I made a mistake!
You don't need a hidden element for this: you might end up having to use hidden elements when using plugins, but it was completely unnecessary here :)
Updated code:
const step = 5;
var mylevel = 0;
const updateProgress = () => {
const currentWidth = Number(document.getElementById("progressvalue").style.width.replace( "%", ""));
if (currentWidth>=100) {
return;
}
else {
document.getElementById("progressvalue").style.width = `${currentWidth+step}%`;
}
const levels = ["silver", "gold", "diamond"];
if(currentWidth > 90 && mylevel < levels.length){
mylevel = mylevel + 1;
document.getElementById("mylevel").textContent = levels[mylevel];
document.getElementById("progressvalue").style.width = "0%";
}
}
const restart = () => {
document.getElementById("progressvalue").style.width = "0%";
}
.progress {
background-color: #ededed;
width: 100%;
overflow: hidden;
}
#progressvalue {
height: 40px;
background-color: lightgreen;
width: 0%;
}
<div class="progress">
<div id="progressvalue"></div>
</div>
<p id="mylevel">silver</p>
<br />
<button type="button" onclick="updateProgress()">
Update Progress
</button>
<button type="button" onclick="restart()">
Restart
</button>

How could I restart this current function

During the use of this function you click a button that will give you a square that will display a colour within a square. However when you click the button 60 times the programme stops working because all the colours have been used. How would I then restart this process so that I can continue clicking ?
<html>
<head>
<script>
var usedColors = [];
function randomColour(){
var colour=[];
colour[0]= '#edf2fb';
colour[1]= '#d7e3fc';
colour[3]= '#c1d3fe';
colour[4]= '#d1d1d1';
colour[5]= '#e1dbd6';
colour[6]= '#e2e2e2';
colour[7]= '#f9f6f2';
colour[8]='#ffc09f';
colour[9]='#ffee93';
colour[10]='#fcf5c7';
colour[11]='#a0ced9';
colour[12]='#adf7b6';
colour[13]='#809bce';
colour[14]='#95b8d1';
colour[15]='#b8e0d2';
colour[16]='#d6eadf';
colour[17]='#eac4d5';
colour[18]='#e8d1c5';
colour[19]='#eddcd2';
colour[20]='#fff1e6';
colour[21]='#f0efeb';
colour[22]='#eeddd3';
colour[23]='#e8dff5';
colour[24]='#fce1e4';
colour[25]='#fcf4dd';
colour[26]='#ddedea';
colour[27]='#daeaf6';
colour[28]='#d3ab9e';
colour[29]='#eac9c1';
colour[30]='#ebd8d0';
colour[31]='#ffe5ec';
colour[32]='#ffc2d1';
colour[33]='#ceb5b7';
colour[35]='#b5d6d6';
colour[36]='#f2f5ff';
colour[37]='#efcfe3';
colour[38]='#eaf2d7';
colour[39]='#b3dee2';
colour[40]='#f8ad9d';
colour[41]='#fbc4ab';
colour[42]='#ffdab9';
colour[43]='#cdb4db';
colour[44]='#ffc8dd';
colour[45]='#ffafcc';
colour[46]='#bde0fe';
colour[47]='#a2d2ff';
colour[48]='#fdffb6';
colour[49]='#caffbf';
colour[50]='#9bf6ff';
colour[51]='#a0c4ff';
colour[52]='#ffc6ff';
colour[53]='#a7bed3';
colour[54]='#c6e2e9';
colour[55]='#f1ffc4';
colour[56]='#ffcaaf';
colour[57]='#dab894';
colour[58]='#fec7bc';
colour[59]='#fcf5ee';
var pick= Math.floor(Math.random()*60);
if(usedColors.includes(pick)){
randomColour();
}
usedColors.push(pick); document.getElementById("colorpad").style.backgroundColor = colour[pick];
console.log(usedColors);
}
</script>
</head>
<body>
<div id="colorpad" style="height: 300px; width: 300px;">
<button onclick="randomColour()">btn</button>
</div>
</body>
</html>
Keep track of the current color:
let curr = 0;
On "Next" button click increment the curr index, and loopback with the help of the Modulo Operator %:
curr += 1;
curr %= colour.length; // On "next" loop back to 0 if we reached the end
Finally there's your color back at 0
console.log(colour[curr]); // '#edf2fb'
Demonstration:
const EL = (sel, EL) => (EL||document).querySelector(sel);
const colors = [
'#edf2fb',
'#d7e3fc',
'#c1d3fe',
'#d1d1d1',
'#e1dbd6',
'#e2e2e2',
'#f9f6f2',
'#ffc09f',
'#ffee93',
'#fcf5c7',
];
const tot = colors.length;
let curr = 0;
const curr_rand = () => curr = Math.floor(Math.random() * tot);
const curr_next = () => (curr += 1, curr %= tot);
const applyColor = () => EL("body").style.background = colors[curr];
EL("#rand").addEventListener("click", () => {
curr_rand();
applyColor();
console.log(curr);
});
EL("#next").addEventListener("click", () => {
curr_next();
applyColor();
console.log(curr);
});
<button type="button" id="rand">Generate</button>
<button type="button" id="next">Next</button>
Here's a snippet using a small factory function to be able to recolor infinitely. The recoloring is done using a randomly shuffled copy of the color array. This way you don't have to check each time if a color is already used.
Furthermore, see comments in the snippet. It uses event delegation for the handler, because it's generally not a good idea to use inline event handlers.
To keep the snippet lean, only 10 colors are used.
const colorize = randomColor(
['#edf2fb', '#d7e3fc', '#c1d3fe', '#d1d1d1', '#e1dbd6',
'#e2e2e2', '#f9f6f2', '#ffc09f', '#ffee93', '#fcf5c7'] );
document.addEventListener(`click`, evt => {
if (evt.target.id === `colorChange`) {
return colorize(document.querySelector(`.color`));
}
});
// randomColor is a factory function, it returns a function.
// The function can use the inner variables as well as the
// [colors] array from the parameter(they are 'closed over').
// The [colors] array is shuffled randomly (Fisher-Yates) and
// on every call (from click) the first color from that shuffled
// array is picked - until it's empty. If [shuffled] is empty
// the original [color] array is reshuffled (into [shuffled]).
// This way the coloring is restarted with a new set of
// random colors.
function randomColor(colors){
const shuffle = array =>
[...Array(array.length)]
.map((el, i) => Math.floor(Math.random() * i))
.reduce( (a, rv, i) =>
([a[i], a[rv]] = [a[rv], a[i]]) && a, array.slice());
// ^ slice copies the original
let shuffled = shuffle(colors);
// return a function
return colorDiv => {
const restarted = !shuffled.length;
shuffled = shuffled.length > 0 ? shuffled : shuffle(colors);
const nwColor = shuffled.shift();
colorDiv.style.backgroundColor = nwColor;
// for demo: color is displayed, and bold/red if [shuffled] is renewed
colorDiv.classList[restarted ? `add` : `remove`](`restart`);
colorDiv.dataset.color = nwColor;
}
}
.color {
width: 100px;
height: 100px;
border: 1px solid #777;
margin: 1rem 0;
text-align: center;
line-height: 100px;
}
.color:before {
content: attr(data-color);
}
.color.restart:before {
color: red;
font-weight: bold;
}
<div class="color"></div>
<button id="colorChange">change</button>

Cycle through, Show and Hide Text/div on first/last click

Sorry if this is a silly question, but I'm making something for a site and can't figure this one out.
How can I make this div appear on the first button click, cycle through the array, then disappear after the last item in the array?
var myArray = ["Hello", "Thank you", "Goodbye"];
var myIndex = 1;
var print = document.getElementById('print');
print.innerHTML = myArray[0]; //Print first value of array right away.
function nextElement() {
print.innerHTML = myArray[myIndex++ % myArray.length];
};
#notfound {
background: #2abfffff;
padding: 19px;
margin: 15px;
color: #fff;
}
<div id="notfound">
<p><span id="print"></span>.</p>
</div>
<a id="click" href="#" onclick="nextElement();">Click</a>
JSfiddle: http://jsfiddle.net/jBJ3B/382/
Because you don't want the div to appear before the first click, remove the line with //Print first value of array right away..
One option is to start with an index of -1, make the element visible when the index is 0, and hide the element when the index is higher or equal to the length of the array:
var arr = ["Hello", "Thank you", "Goodbye"];
var index = -1;
var print = document.getElementById('print');
function nextElement() {
index++;
if (index >= arr.length) {
print.style.visibility = 'hidden';
return;
}
if (index === 0) print.style.visibility = 'visible';
print.textContent = arr[index];
}
#notfound {
background: #2abfffff;
padding: 19px;
margin: 15px;
color: #fff;
}
.print {
visibility: hidden;
}
<div id="notfound">
<p><span id="print"></span>.</p>
</div>
<a id="click" href="#" onclick="nextElement();">Click</a>
If you need the element to re-appear on further clicks, then use modulo to set index to -1 at the end:
var arr = ["Hello", "Thank you", "Goodbye"];
var index = -1;
var print = document.getElementById('print');
function nextElement() {
index++;
if (index >= arr.length) {
print.style.visibility = 'hidden';
index = -1;
return;
}
if (index === 0) print.style.visibility = 'visible';
print.textContent = arr[index];
}
#notfound {
background: #2abfffff;
padding: 19px;
margin: 15px;
color: #fff;
}
.print {
visibility: hidden;
}
<div id="notfound">
<p><span id="print"></span>.</p>
</div>
<a id="click" href="#" onclick="nextElement();">Click</a>
You can check inside nextElement() if that element was the last one, and then just hide the div.
function nextElement() {
print.innerHTML = myArray[myIndex++%myArray.length];
if(myIndex>myArray.length){
document.getElementById("notfound").style.visibility = "hidden";
}
};
JSFiddle: http://jsfiddle.net/jBJ3B/384/
Is it what you trying to do:http://jsfiddle.net/yvbenitah/jBJ3B/393/.
If yes only add that line:
document.getElementById('notfound').style.display = 'none';

Getting a position of an element in a 2D array

So I'm building a a turn based board game which needs to contain 2 player that can move across the map. I'm stuck at getting the position of the player(which is just a simple div element) inside of that 2D array. I've tried using indexOf, but even tho it's placed inside an onclick function, always returns 0.
The html code contains just of few div's with col classes:
And here is the JavaScript code (btw it contains some unnecessary stuff that I've just added for test purposes) :
let row = document.querySelector('.row');
let fields = document.getElementsByClassName('col-md-2')
let fieldsArr = Array.from(fields);
let header = document.getElementById("clicked");
let cols = header.getElementsByClassName("col-md-2");
let player = document.getElementById('player');
let player2 = document.getElementById('player2');
let blockedField = document.getElementsByClassName('blocked');
fieldsArr.sort(function() {
return 0.5 - Math.random();
}).forEach(function(el) {
row.appendChild(el);
});
// ADD AN EVENT LISTENER AND LISTEN FOR COLS ID
function replyClick(e) {
e = e || window.event;
e = e.target || e.srcElement;
if (e.nodeName === 'DIV') {
let changable = e.id;
//console.log(changable);
}
}
// CREATE A 2D ARRAY (MAP)
var map = [];
while (fieldsArr.length) map.push(fieldsArr.splice(0, 6));
// ON CLICK ADD A CLASS OF ACTIVE
for (var i = 0; i < cols.length; i++) {
cols[i].addEventListener("click", function() {
var current = document.getElementsByClassName("active");
current[0].className = current[0].className.replace(" active", "");
this.className += " active";
});
}
// MOVE PLAYER ONE ACROSS THE MAP
function movePlayer(multWidth, multHeight) {
$(".active").append(player);
if ((row).click > multWidth) {
alert(1)
}
}
// MOVE PLAYER 2 ACROSS THE MAP
function movePlayer2() {
$(".active").append(player2);
}
// MAKE GRAYED OUT FIELD UNAVALIABLE AND SHOW AN ALERT
$(blockedField).css("pointer-events", "none");
// APPEND PLAYER1(2) TO THE FIRST(LAST) FIELD ON THE MAP
map[0][0].appendChild(player);
map[5][5].appendChild(player2);
// GET PLAYERS CURRENT POSITION
$(row).click(function() {
let current = player.offsetTop;
});
const widthAllowed = 3 * 156;
const heightAllowed = 3 * 146;
// LIMIT PLAYER MOVES
let player1Moves = 3;
player2Moves = 3;
$(row).click(function() {
movePlayer();
let remainingMoves = player1Moves -= 1;
if (remainingMoves === 0) {
alert("You don't have any more moves. Player's 2 turn.");
$(player).css("pointer-events", "none");
$(row).click(movePlayer2);
}
})
for (var x = 0; x < map.length; x++) {
for (var y = 0; y < map[x].length; y++) {
console.log(x, y);
}
}
console.log(map);
console.log(map[2][5]);
console.log(map[5][0]);
You should take some beginner jquery/javascript course, since your question is very simple and you will find the whole programming thing way easier with a few basic concepts (like selectors, events and callbacks)
That said, here is a basic example of how to return the div element that contains the player element and how to use event attachment instead of inline events.
let row = $('.row');
row.on('click', replyClick);
function replyClick(e) {
var targetRow = $(e.target);
$('.row > div.active').removeClass('active');
targetRow.addClass('active');
var player = $('.row div.player');
alert(player.parent().attr('id'));
};
.player {
width: 20px;
height: 20px;
background: red;
}
.row > div {
padding: 10px;
width: 20px;
height: 20px;
border: 1px solid red;
}
.row > div.active {
background: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<div class="row">
<div id="col1" class="col-md-2">
<div class="player"></div>
</div>
<div id="col2" class="col-md-2 blocked"></div>
<div id="col3" class="col-md-2 active"></div>
<div id="col4" class="col-md-2"></div>
</div>
</div>

Categories