I'm building a quiz app just for fun. But I'm not getting what I want.
Basically, I have a question and answers (a-e options).
When I click a answer, I want to change the background (card) dynamically just for the selected. If was wrong, change this color to red and the correct one for green.
Simplified html
<ion-row>
<ion-col size="12" style="padding: 0;">
<ion-card class="card__wrapper card__{{answer.option}}" *ngFor="let answer of question.answers" tappable (click)="chooseAnswer(answer)" [style.backgroundColor]="answer.is_correct ? correct : 'color'+answer.option">
<ion-card-content class="card__content">
<ion-row>
<ion-col size="2" style="padding: 0;">
<div class="option__wrapper">
<p class="answer__option">{{answer.option}}</p>
</div>
</ion-col>
<ion-col size="10" style="padding: 0; margin: auto;">
<p style="text-align: left; margin: 0;"[innerHTML]="answer.description"></p>
</ion-col>
</ion-row>
</ion-card-content>
</ion-card>
</ion-col>
</ion-row>
Simplified .ts
public correct: string = '#fff';
public wrong: string = '#fff';
public slidePage = '0';
public colorA = '#fff';
public colorB = '#fff';
public colorC = '#fff';
public colorD = '#fff';
public colorE = '#fff';
chooseAnswer(answer) {
if (answer.is_correct) {
this.correct = '#00e676';
} else {
switch (answer.option) {
case "A":
this.colorA = 'red';
break;
case "B":
this.colorB = 'red';
break;
case "C":
this.colorC = 'red';
break;
case "D":
this.colorD = 'red';
break;
case "E":
this.colorE = 'red';
break;
}
this.correct = '#00e676';
}
}
So there are two cases:
Select correct answer
Set background of the selected answer to green
Select wrong answer
Set background of the selected answer to red and set background of the correct answer to green.
Related
So i have been looking on internet for some kinda of dialog/modal in vuejs2 that pops up when exit is clicked, that asks us if we are sure that we want to leave. And when click yes, function is called , and when clicked no, nothing happens just dialog/modal is exited. I was not able to find anything on the vuejs.org.Im not using bootstrap and not using vutify. Any suggestions how this can be done, that popup should blackout the rest of the screen and poput in the middle of the screen.
Its very easy to create your own dialog.
Here is a small component that I created for you.
https://jsfiddle.net/ew1c3z6u/
Im really new to veujs but this should work for you
var component =new Vue({
el: '#dialog-container',
methods:{
show:(event)=> {
component.visibility = true;
// maybe you could ajest the position of the dialog here.
// eg top, center etc
},
onSave:(event)=> {
alert("save clicked")
component.visibility = false;
},
onCancel:(event)=> {
alert("cancel clicked")
component.visibility = false;
}
},
data: {
buttons:[], // you could have a list a dynamic buttons here
content:"this is the content of the dialog",
visibility:false,
title: 'this is the title of the dialog'
}
})
.dimBackground{
background:black;
opacity:0.5;
z-index:90;
position:fixed;
width:100%;
height:100%;
left:0;
top:0;
}
#dialog-container > #dialog
{
background:white;
z-index:100;
min-width:400px;
min-height: 100px;
border:1px black solid;
display:inline-block;
padding:0;
position:fixed;
left:30%;
top:30%;
overflow-x:hidden;
overflow-y:auto;
}
#dialog-container > #dialog > h1{
width:99%;
background:blue;
color:white;
margin:0;
font-size:20px;
padding-top:5px;
padding-bottom:5px;
padding-left:5px;
}
#dialog-container > #dialog > .content{
padding:5px;
}
#dialog-container > #dialog > h1 > div{
display:inline-block;
float:right;
position:relative;
top:-3px;
padding-right:5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.2.0/vue.js"></script>
<div id="dialog-container">
<input type="button" value="show dialog" v-on:click="show" />
<div class="dimBackground" v-if=visibility> </div>
<div id="dialog" v-if=visibility>
<h1>
{{title}}
<div>
<button v-on:click="onSave" >
Save
</button>
<button v-on:click="onCancel">
Cancel
</button>
</div>
</h1>
<div class="content">
{{content}}
</div>
</div>
</div>
I have a scenario where 15 questions are there and i do have to select the answer either by selecting radiobutton or checkbox or Yes/No button or have to enter some text in textarea.
My following code successfully selecting the answer randomly whether its a radio/checkbox or Yes/No button and displays the selected option as an answer along with question on console.
But how do i check if its textarea and need to enter something with 'sendKeys? And how do i select more than one checkboxes? And how do i display the answer Yes or No onconsole?
public void AssessmentTest() throws Exception
{
List<WebElement>totalQSN = driver.findElements(By.xpath("//div[#id='assessmentQuestionAnswersContainer']/div"));
List<WebElement> mainQuestions = driver.findElements(By.xpath("//div[#id='assessmentQuestionAnswersContainer']/div/div[2]/div"));
System.out.println("The Questions are::");
for(int i=0; i<totalQSN.size()-5; i++)
{
System.out.println("QUESTION:- " + mainQuestions.get(i).getText() + "["+ i +"]" );
Random rnd = new Random();
List<WebElement> subOptions = totalQSN.get(i).findElements(By.tagName("input"));
WebElement sValue = subOptions.get(rnd.nextInt(subOptions.size()));
sValue.click();
List<WebElement> subQsnList = driver.findElements(By.xpath("//div[#id='assessmentQuestionAnswersContainer']/div/div[3]/div/span/span"));
System.out.println(subOptions.size());
for(int j=0; j<subOptions.size(); j++)
{
if(subOptions.get(j).isSelected())
{
String selectedAnswer= subQsnList.get(j).getText();
System.out.println("ANSWER: - " + selectedAnswer);
System.out.println("\n");
}
}
} }
HTML Code is as under for each type of question.
<div id="individualQuestionAnswerContainer147" class="individual-question-answer-container" style="display: block;" xpath="1">
<div class="individual-questions-count-container"></div>
<div id="questionContainer147" style="clear: both; float: left;"></div> //Contains Question
<div id="questionAnswerContainer147" class="answers-container"></div> //Contains Answers
</div>
If the question having checkboxes, the code is
<div id="individualQuestionAnswerContainer148" class="individual-question-answer-container" style="" xpath="2"> Contains 4 checkbox(divs)
<div class="individual-questions-count-container"></div>
<div id="questionContainer148" style="clear: both; float: left;"></div>
<div id="questionAnswerContainer148" class="answers-container" style="">
<div class="answer-text">
<span class="answer-text-inner btn-assessment-answer">
<input type="checkbox" name="Checkbox148" id="Checkbox449" class="radio-assessment-answer">
<span style="display: table;">
Good
</span>
</span>
</div>
<div class="answer-text">
<span class="answer-text-inner btn-assessment-answer">
<input type="checkbox" name="Checkbox148" id="Checkbox450" class="radio-assessment-answer">
<span style="display: table;">
Mold
</span>
</span>
</div>
<div class="answer-text"></div>
<div class="answer-text"></div>
</div>
</div>
If question having 2 buttons(Yes/No), the code is
<div id="individualQuestionAnswerContainer155" class="individual-question-answer-container" style="" xpath="7"> Contains 2 options Yes or No
<div class="individual-questions-count-container"></div>
<div id="questionContainer155" style="clear: both; float: left;"></div>
<div id="questionAnswerContainer155" class="answers-container" style="">
<input type="button" value="Yes" id="Button477" class="btnClass_155 btn-assessment-answer" style="">
<input type="button" value="No" id="Button478" class="btnClass_155 buttonClicked btn-assessment-answer">
</div>
</div>
If question having textarea, the code is
<div id="questionAnswerContainer38" class="answers-container" xpath="1">
<textarea maxlength="50000" rows="2" cols="100" id="FreeTextarea38"></textarea>
</div>
Try using this structure..Hope this helps.
public void AssessmentTest() throws Exception
{
List<WebElement>totalQSN = driver.findElements(By.xpath("//div[#id='assessmentQuestionAnswersContainer']/div"));//Assuming this xpath is correct
List<WebElement> mainQuestions = driver.findElements(By.xpath("//div[#id='assessmentQuestionAnswersContainer']/div/div[2]/div")); //Assuming this xpath is correct
System.out.println("The Questions are::");
for(int i=0; i<totalQSN.size()-5; i++)
{
System.out.println("QUESTION:- " + mainQuestions.get(i).getText() + "["+ i +"]" );
Random rnd = new Random();
String webeleTag=totalQSN.get(i).getTagName();
if(webeleTag.equals("input"))){
String webeleType=totalQSN.get(i).getAttribute("type");
switch(webeleType){
case:"checkbox":
//your code to select check box
case:"button":
//Only click event on answer
default:
}
}
else if(webeleTag.equals("textarea")){
//your code
}
else{
//Not text area,checkbox or radio something else
}
}
}
To detect if it is a text area, from the top of my head you can go
for .getTagName() this will return the tag of the element.
To get all the checkboxes you can use driver.findElements(By.id("questionAnswerContainer148")).toArray(new WebElement[0]) , this will return an array with the checkboxes and you can use some logic to click in the items you want from the list.
For the yes/no, I think that the driver.findElement(by).getAttribute("value") will return the content of the attribute.
Hope this helps you.
I have implemented sortablejs in Polymer2.0 element. I am able to drag and drop the item from group. The issue I am facing now is that randomly, not sure why and how, but 2 cards or items gets moved in a group list. Here's the screenshots.
todos is an object which contains group of lists which have array of items.
List
https://www.dropbox.com/s/9wp6vv668p3ckr2/Screenshot%202019-04-30%2007.18.16.png?dl=0
End state when dropped (you see 2 cards moved to the new column which I don't want. I only wanted one card to move)
https://www.dropbox.com/s/int4uyyl3945tjv/Screenshot%202019-04-30%2007.18.50.png?dl=0
Code: Polymer element html
<div class="boardÂ__sprint">
<template is="dom-repeat" items="{{todos}}" as="row" restamp>
<div class="list">
<div class="listÂ-content">
<div style="float: left; width: 100%; text-align: center;">
<div style="float: left; width: 80%; text-align: left; padding-top: 10px;">
<h7 style="color: black; font-size: 20px; font-weight: 800; padding-left: 10px;margin-top: 5px;">
[[row.tasks.length]]
</h7>
<h7 style="color: black; font-size: 12px; font-weight: 200; padding: 2px; margin-top: 5px;">
[[row.title]]
</h7>
</div>
<div style="float: left; width: 20%; text-align: center;">
<paper-icon-button icon="icons:delete-sweep" style="color: grey;" id="deleteNote" row="[[row]]"
on-tap="_removeColumnTriggerDialog"></paper-icon-button>
</div>
</div>
<div style="display: table;">
<div style="width: 90%; height: 3px; background: #0c66b5;">
<h7> </h7>
</div>
<div id="myid[[row.id]]" class="list-group" style="min-height: 120px;">
<template is="dom-repeat" items="{{row.tasks}}" as="todo" restamp>
<!-- <div class$="{{determineDragable(todo)}}"> -->
<div class="item">
<div class="ticket" data-index$="{{todo.id}}">
<paper-card style="float:center; width: 100%;" class="singleColor" data-index$="{{todo}}"
data-index$="{{row}}">
<div style="float:left; width: 15%" style$="{{getRandomInt(0, 20)}}">
<h7> </h7>
</div>
<div style="width: 100%">
<div style="float: left; width: 15%; vertical-align:center">
<px-icon icon="px-vis:pin"></px-icon>
</div>
<div style="float: left; width: 70%">
<h7 class="banksTitle" style="color: black; font-size: 12px; text-align:left;">
<b>[{{index}}]</b> [[todo.actTitle]]
</h7>
<h7 class="banksTitle" style="color: grey; font-size: 12px; text-align:left;">
[[todo.actDesc]]
</h7>
</div>
<template is="dom-if" if="{{checkDummy(todo)}}">
<div style="float: left; width: 15%;">
<paper-icon-button icon="icons:close" style="color: grey;" id$="bt_readmore"
todo="[[todo]]" row="[[row]]" on-tap="_moveDel"></paper-icon-button>
</div>
</template>
<template is="dom-if" if="{{checkDummyNot(todo)}}">
<div style="float: left; width: 15%;">
<paper-icon-button icon="image:crop-square" style="color: grey;" id$="bt_readmore"
todo="[[todo]]" row="[[row]]" on-tap=""></paper-icon-button>
</div>
</template>
</div>
<div>
<h5> </h5>
</div>
<div style="width: 100%;display: table;">
<div style="float: left; width: 15%;">
</div>
<div style="float: left; width: 70%; text-align: center;">
<template is="dom-if" if="{{checkDummy(todo)}}">
<paper-icon-button icon="av:playlist-add-check" style="color: green;"
id$="bt_readmore" todo="[[todo]]" row="[[row]]" on-tap=""></paper-icon-button>
</template>
<template is="dom-if" if="{{checkDummy(todo)}}">
<paper-icon-button icon="editor:attach-file" style="color: maroon;" id$="bt_readmore"
todo="[[todo]]" row="[[row]]" on-tap=""></paper-icon-button>
</template>
<template is="dom-if" if="{{checkDummy(todo)}}">
<paper-icon-button icon="editor:border-color" style="color: grey;" id$="bt_readmore"
todo="[[todo]]" row="[[row]]" on-tap=""></paper-icon-button>
</template>
</div>
<div style="float: right; width: 15%;">
</div>
</div>
</paper-card>
</div>
</div>
</template>
</div>
</div>
<div>
<h5> </h5>
</div>
<div class="addTicket">
<paper-button raised class="blue" on-tap="_addTicketDialog" row={{row}}>Add Ticket</paper-button>
</div>
</div>
</div>
</template>
</div>
and the JS script specific to onAdd event of sortablejs
_todosChanged() {
setTimeout(() => {
console.log('this.todos.length = ' + this.todos.length);
var self = this;
if (this.todos !== null || this.todos !== undefined) {
var lowestOrder = 0;
var highestOrder = 0;
var options = {
group: 'shared',
animation: 200,
sort: false,
draggable: ".item",
onAdd: function (evt) {
console.log('---FROM----');
console.log(evt.from.id);
console.log('---TO----');
console.log(evt.to.id);
console.log('---ITEM----');
console.log(evt.item.innerText);
var foundFrom = false;
var fromId = evt.from.id.substr('myid'.length);
var fromCol;
var foundTo = false;
var toId = evt.to.id.substr('myid'.length);
var toCol;
console.log('fromId =' + fromId + ' toId =' + toId);
self.todos.forEach(child => { //todos = 1, 3, 4 & row = 3
if (!foundTo) {
if (child.id === toId) {
foundTo = true;
toCol = child;
}
}
if (!foundFrom) {
if (child.id === fromId) {
foundFrom = true;
fromCol = child;
}
}
});
console.log('toCol = ' + JSON.stringify(toCol));
console.log('fromCol = ' + JSON.stringify(fromCol));
//find item in from col
var str = evt.item.innerText;
var itemKey = str.substr(0, str.indexOf(':'));
itemKey = itemKey.substr(itemKey.indexOf('KEY-')).substr('KEY-'.length);
console.log('itemKey = ' + itemKey);
var arrItemToRemove = fromCol.tasks;
console.log('arrItemToRemove = ' + JSON.stringify(arrItemToRemove));
var indexItem = -1;
for (var i = 0; i < arrItemToRemove.length; i++)
if (arrItemToRemove[i].id === itemKey) indexItem = i;
console.log('indexItem = ' + indexItem);
if (indexItem < 0 || indexItem > arrItemToRemove.length) {
document.getElementById('toastError').show('No item found');
} else {
// console.log('indexItem=' + indexItem);
var newItemToPush = arrItemToRemove[indexItem];
console.log('newItemToPush=' + JSON.stringify(newItemToPush));
//now add the item to the right
var arr = toCol.tasks;
if (arr === null || arr === undefined) arr = [];
arr.push({
'actTitle': newItemToPush.actTitle,
'actDesc': newItemToPush.actDesc,
'actDt': newItemToPush.actDt,
'parent': toCol.order,
'id': newItemToPush.id
});
console.log('arr=' + JSON.stringify(arr));
self.$.query.ref.child(toCol.$key).child('tasks').set(arr);
var nwArr = arrItemToRemove.splice(indexItem, 1);
document.getElementById('toastShort').show('Data moved: ' + newItemToPush.actTitle);
self.$.query.ref.child(fromCol.$key).child('tasks').set(arrItemToRemove);
}
},
};
this.todos.forEach(child => {
if (lowestOrder > child.order) lowestOrder = child.order;
if (highestOrder < child.order) highestOrder = child.order;
// console.log(child.id);
var selector = this.shadowRoot.querySelector('#myid' + child.id);
Sortable.create(selector, options);
});
console.log('lowestOrder=' + lowestOrder + ' highestOrder=' + highestOrder);
this.set('order', highestOrder);
}
});
}
Ok ... this is what I did to resolve the issue
firebase query is async so I used observer function to update the dummy variable which is used in dom-template. I used async to do that.
The real issue was when you remove element from list that sortablejs has used to render the items. By use of Dummy variable that is copy of firebase object I was able to avoid this issue.
I offline sync the object when user leaves the page. It works fine now.
I am running one jquery kendo grid row template where i am showing some content with images.Below is the code :
<table id="grid" style="width:100%">
<colgroup>
<col class="photo" />
<col class="details" />
<col />
</colgroup>
<thead style="display:none">
<tr>
<th>
Details
</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="3"></td>
</tr>
</tbody>
</table>
<script id="rowTemplate" type="text/x-kendo-tmpl">
<tr>
<td style="width:30%">
div class="row">
<div id="dvImage" class="col-sm-4" style="width:118px">
#= imagelink #
</div>
<div class="col-sm-8" style="width:400px">
<span class="name" style="font-size:14px; color:green">#: Link #</span>
</div>
</div>
</td>
</tr>
</script>
<style>
.name {
display: block;
font-size: 1.3em;
}
.k-grid-header .k-header {
padding: 0px 20px;
}
.k-grid-content {
overflow-y: auto;
}
.k-grid tr td {
background: white !important;
border: 0 !important;
border-color: transparent;
}
.k pager-wrap {
border-width: 1px !important;
border-color: #ccc;
}
.k-block, .k-widget, .k-input, .k-textbox, .k-group, .k-content, .k-header, .k-filter-row > th, .k-editable-area, .k-separator, .k-colorpicker .k-i-arrow-s, .k-textbox > input, .k-autocomplete, .k-dropdown-wrap, .k-toolbar, .k-group-footer td, .k-grid-footer, .k-footer-template td, .k-state-default, .k-state-default .k-select, .k-state-disabled, .k-grid-header, .k-grid-header-wrap, .k-grid-header-locked, .k-grid-footer-locked, .k-grid-content-locked, .k-grid td, .k-grid td.k-state-selected, .k-grid-footer-wrap, .k-pager-wrap, .k-pager-wrap .k-link, .k-pager-refresh, .k-grouping-header, .k-grouping-header .k-group-indicator, .k-panelbar > .k-item > .k-link, .k-panel > .k-item > .k-link, .k-panelbar .k-panel, .k-panelbar .k-content, .k-treemap-tile, .k-calendar th, .k-slider-track, .k-splitbar, .k-dropzone-active, .k-tiles, .k-toolbar, .k-tooltip, .k-button-group .k-tool, .k-upload-files {
border-color: transparent;
}
.col-md-2 {
width:118px
}
.col-md-3 {
width:25%
}
</style>
In the above code i have Image and description which i am showing but for some of the rows i don't have image but still it's containing the space. So here i need that if image is null for particular row then it should hide that image column. I tried like this but did not get any luck.
Below is the code:
$("#grid").kendoGrid({
autoBind: false,
dataSource: {
transport: {
read: {
url: "/Home/GetSearchData",
type: "POST",
contentType: "application/json; charset=utf-8",
dataType: "json",
data: { searchTerm: $('[id*=hdnHomeSearch]').val() }
},
parameterMap: function (data, operation) {
return kendo.stringify(data);
}
},
pageSize: 10,
schema: {
parse: function (data) {
debugger;
var items = [];
var chkCorrectVal = 0;
var context = $('#dvImage');
for (var i = 0; i < data.data.length; i++) {
if (data.data[i].CorrectValue != null && data.data[i].SearchValue != null) {
$("#spnSR")[i].innerHTML = "<b>" + "Get results for this text: " + "</b>" + data.data[i].CorrectValue;
$("#spnSV")[i].innerHTML = "<b>" + "Searched for this text: " + "</b>" + data.data[i].SearchValue;
chkCorrectVal = 1;
}
else {
if (chkCorrectVal == 0) {
$("#spnSR").hide();
$("#spnSV").hide();
}
}
if (!data.data[i].imagelink) {
var getContext = $(context[i]);
data.data[i].imagelink = "";
$(context[i]).addClass('hidden');
}
}
var product = {
data: data.data,
total: data.total
};
items.push(product);
return (items[0].data);
},
}
},
dataBound: function () {
DisplayNoResultFound($("#grid"));
},
serverPaging: true,
pageable: {
refresh: true,
pageSizes: true
},
rowTemplate: kendo.template($("#rowTemplate").html()),
});
});
One more example i am pasting here where i am trying to get the same results and that is working fine for me.
Below is the code:
<input type="submit" id="soltitle" value="#1"/>
<div class="row">
<div class="col-md-2" id="hell1">
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title"></h4>
</div>
<div id="timeline1" class="panel-collapse collapse">
<div class="panel-body">
<a href="#" class="thumbnail">
<img class="img-responsive" src="http://placehold.it/250x160" alt="Thumb11" />
</a>
</div>
</div>
</div>
</div>
<div class="col-md-4">
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title"></h4>
</div>
<div id="timeline1" class="panel-collapse collapse">
<div class="panel-body">
<a href="#" class="thumbnail">
<img class="img-responsive" src="http://placehold.it/250x160" alt="Thumb11" />
</a>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript">
$(document).ready(function () {
$('#soltitle').click(function () {
$('#hell1')
// Find parent with the class that starts with "col-md"
// Change class to "col-md-3"
.closest('[class^="col-md"]')
.toggleClass('col-md-2 col-md-2 hidden')
// Find siblings of parent with similar class criteria
// - if all siblings are the same, you can use ".siblings()"
// Change class to "col-md-2"
//.siblings('[class^="col-md"]')
// .removeClass('col-md-3')
// .addClass('col-md-2');
});
});
</script>
in this example i am hiding first column in button click event and that is working fine.
The problem is that you toggle the class for all rows where the image does not exist. Each time you toggle those and toggle again, the second toggle negates the first one. If the rows where the if is evaluated to true is pair, then the last toggle was a negation.
It is not clear whether you need to hide the whole column if you find one such row, or you need to hide the column only for the affected row specifically. Also, your if is incorrect.
If you want to hide the whole column if at least such a row exists, then this might be the solution:
var shouldShow = true;
for (var i = 0; shouldShow && (i < data.data.length); i++) {
if (!data.data[i].imagelink) {
$(".imageClass").addClass('hidden');
shouldShow = false;
}
}
If you want to do it only for the affected row, then something like this might help you:
var context = $(".imageClass");
for (var i = 0; i < data.data.length; i++) {
if (!data.data[i].imagelink) {
$(context[i]).addClass('hidden');
}
}
The code assumes you have a single column having imageClass.
EDIT
It turned out that the .hidden class was not defined. There are two possible solutions, you can choose either of them.
Solution1: replace .addClass("hidden") with .hide()
Solution2: Add the following rule to the CSS code: .hidden {display: none;}
On input focus I want to change the color of the label element. How can I achieve this in less?
.control-label{
color: #gray-light;
}
.controls{
input,
textarea{
background-color:red;
&:focus{
.control-label &{
color: red; //HERE
}
}
}
HTML:
<div class="control-group">
<label class="control-label" for="inputEmail">Firstname</label>
<div class="controls">
<input type="text" id="inputEmail" placeholder="Firstname">
</div>
</div>
One solution would be to use the :focus-within selector.
So, you'd do something like the below. Assuming that you always have an input of some description inside of a control-group, it will style the label whenever the input is focused on.
control-group {
&:focus-within {
control-label {
color: red;
}
}
}
More information can be found here: https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-within
I don't think you can without changing your HTML, see also: Is there any way to hover over one element and affect a different element?, your elements should be direct siblings. (LESS don't help to solve your problem here, LESS generate CSS and it seems impossible to do in CSS)
Possible suggestion:
input:focus + .control-label
{
background-color:purple;
color: red;
}
.controls > input
{
float:right;
}
<div class="controls">
<input type="text" id="inputEmail" placeholder="Firstname">
<label class="control-label" for="inputEmail">Firstname</label>
</div>
Or solve your problem with javascript: https://stackoverflow.com/a/20226218/1596547
Use Flexbox
CSS is cascading, i.e. affected by the order that elements appear in the DOM. To be able to select the label only when the input is focused (input:focus + label), the label needs to come after the input, so;
Put the input before the label in the DOM and then use flexbox to reverse the order that they appear on the page.
.input-group {
display: flex;
flex-direction: column-reverse;
}
input:focus + label {
color: green;
}
<div class="input-group">
<input value="Input" />
<label>Label</label>
</div>
One solution would be to move the label below the input in the DOM but position them absolutely (to the parent) so the label looks to be above the input field:
<div>
<input type="text"/>
<label>Text</label>
</div>
In CSS move the label to the top, the input to the bottom:
label {
position: absolute
top: 0
}
input {
position: absolute
bottom: 0
}
And use the :focus state to change the style of the label:
input:focus + label {
color: red
}
See example:
http://codepen.io/robcampo/pen/zGKLgg
On focus, the label turns red. No JS required.
control-group {
&:focus-within {
control-label {
color: red;
}
}
}
loads of hearts to this person. Nothing was working and this worked in ion-label too . Accepted answer. Stack overflow does not allow to comment (below 50 reputation). So writing seperately <3
I hope I am not too late to answer this. With the new :has psudo-class we can achieve it without changing the HTML,
HTML:
<div class="control-group">
<label class="control-label" for="inputEmail">Firstname</label>
<div class="controls">
<input type="text" id="inputEmail" placeholder="Firstname">
</div>
</div>
CSS:
.control-group:has(input:focus) label{
color: red;
}
This approach is simple and cleaner.
Note: it is not supported by firefox yet.
The easy way is to use :focus-within check developer mozilla
.control-group:focus-within .control-label {
color: red;
}
Or
.control-group:focus-within label {
color: red;
}