How to customize ion-range in ionic 5? - html

I am looking for a solution with my current issue regarding on how to customize the ion-range based on the wireframe. As you can see below the difference between the wireframe and the actual worked I made.
Wireframe Design
My actual work
Above, you can see the difference between the two. My question is, is there anyway or solution that I can do to get the actual look of the wireframe. Based on the wireframe, as the user moves the tick, the label aligned with the tick should be color blue also.
These are my codes I used and produced my actual work.
.html
<div class="slidecontainer">
<ion-range
class="range-position"
min="5"
max="100"
dualknobs="true"
pin="false"
snaps="true"
ticks="false"
value="0"
snaps color="primary"
list='tickmarks'>
</ion-range>
<div id="tickmarks" class="tick-position">
<p>5</p>
<p>10</p>
<p>25</p>
<p>50</p>
<p>75</p>
<p>100</p>
</div>
</div>
.scss
// Customize Slider
#tickmarks {
display: flex;
justify-content: space-between;
padding: 0 25px;
}
#tickmarks p {
position: relative;
display: flex;
justify-content: center;
text-align: center;
width: 1px;
background: #ccd3da;
height: 10px;
line-height: 40px;
margin: 0 0 20px 0;
font-family: 'Archivo';
font-size: 12px;
}
Hope you can help so that I can move forward with my task. Thank you so much

You can Use (ionChange) event to make it work.
<ion-range
class="range-position"
min="5"
max="100"
dualknobs="true"
pin="false"
snaps="true"
ticks="false"
value="0"
step="25" // use step attribute for sure event value
snaps color="primary"
list='tickmarks'
(ionChange)="changeFunction($event)">
</ion-range>
<div id="tickmarks" class="tick-position">
<p [ngClass]="selectedValue == 0 ? 'active' : null">5</p>
<p [ngClass]="selectedValue == 25 ? 'active' : null">25</p>
<p [ngClass]="selectedValue == 50 ? 'active' : null">50</p>
<p [ngClass]="selectedValue == 75 ? 'active' : null">75</p>
<p [ngClass]="selectedValue == 100 ? 'active' : null">100</p>
</div>
.ts
selectedValue;
changeFunction($event){
this.selectedValue = $event.detail.value;
}

You can have the the tick marks underneath the ion-range component react to the selected value in the range, like below.
Add a function that listens to the ionChange event to <ion-change>. Use that function in your component class to update a value. Then you can use that value in your template to indicate which tick should be highlighted (gets the selected CSS class).
range.component.html - for single range (one knob)
<div class="range-container">
<ion-range
(ionChange)="setValue($event)"
[value]="currentValue"
color="primary"
dual-knobs="false"
max="100"
min="0"
pin="false"
snaps="true"
step="25"
ticks="false"
>
</ion-range>
<ul class="tick-marks">
<li
*ngFor="let number of [0, 25, 50, 75, 100]"
[class.selected]="number === currentValue"
>
{{number}}
</li>
</ul>
</div>
range.component.html - for dual knobs
<div class="range-container">
<ion-range
(ionChange)="setDualValues($event)"
[value]="currentDualValues"
color="primary"
dual-knobs="true"
max="100"
min="0"
pin="false"
snaps="true"
step="25"
ticks="false"
>
</ion-range>
<ul class="tick-marks">
<li
*ngFor="let number of [0, 25, 50, 75, 100]"
[class.selected]="number === currentDualValues.lower || number === currentDualValues.upper"
>
{{number}}
</li>
</ul>
</div>
range.component.ts- the component file
#Component({
selector: 'app-range',
styleUrls: ['./range.component.scss']
templateUrl: './range.component.html'
})
export class RangeComponent {
currentValue = 0;
currentDualValues = {
lower: 25,
upper: 50
};
// use this for single slider
setValue($event: Event): void {
this.currentValue = parseInt(($event.target as HTMLInputElement).value, 10);
}
// use this for dual sliders (dual knobs)
setDualValues($event: Event): void {
this.currentDualValues = JSON.parse(JSON.stringify(($event.target as HTMLInputElement).value));
}
}
Finally, in your CSS add the .selected class to style selected numbers as you wish, for instance like this (you will probably need to change padding of ul.tick-marks to make sure the tick marks align properly with the range selector):
range.component.scss
.range-container {
display: flex;
flex-direction: column;
width: 100%;
.tick-marks {
display: flex;
justify-content: space-between;
list-style: none;
margin: 0;
padding: 0;
li {
color: var(--ion-color-dark);
position: relative;
&::before {
background-color: var(--ion-color-dark);
content: '';
display: block;
height: 20px;
left: 50%;
position: absolute;
width: 1px;
top: -20px;
}
&.selected {
color: var(--ion-color-primary);
&::before {
background-color: var(--ion-color-primary);
}
}
}
}
}
See also this stackblitz for reference.

Related

How to wrap text in a option inside select box

How to wrap text in a option inside select box? you can see the given below image
<div class=" assignment">
<div style="display: flex;">
<i class="fa fa-cube"></i> <strong>Dropdown</strong>
<select id="" class="" style="/* width: 50%; */overflow: hidden; overflow-wrap: break-word; width: 100%;">
<option id="default" value="">Select PickUp Point</option>
<option value="B-01-62,Room - Bereich IT Site Service,Mooswaldallee 1, FREIBURG, , 79090, Pickup Timings - Mo-Fr: 09:00-12:00 and 13:00-16:00" ;">Bccnew-01-62,Room - Bereich coupan Site university,Mooswalgfr ghytdallee 1, FREIBBNHRYURG, , 7900090, Pickup Timings - Mo-Fr: 09:00-12:00 and 13:00-16:00</option>
</select>
<span> </span> <br> <br> <button id="digitalDeliverybtn" class="button pull-right">Submit</button>
</div>
</div>
enter image description here
You can simulate a select box and style it any way you want.
const sel = document.querySelector("#selected");
/* Create an array with the options */
const opt = [...document.querySelectorAll(".option")];
const inp = document.querySelector("#sel");
sel.addEventListener("click", () => {
const opts = document.querySelector("#options");
if (opts.classList.contains("open")) {
/* If the <ul> is visible, hide it */
opts.classList.remove("open");
} else {
/* If the <ul> is hidden, show it */
opts.classList.add("open");
}
});
opt.forEach((e, i, o) => {
/* Add an event listener for each option */
o[i].addEventListener("click", () => {
/* Store the value of the option in a variable */
const chosen = e.querySelector("span").innerHTML;
const opts = document.querySelector("#options");
/* Assign the value of the option to the select box */
sel.innerHTML = chosen;
/* Assign the value of the option to the hidden input field */
inp.value = chosen;
/* And close the <ul> */
opts.classList.remove("open");
});
})
.container {
display: flex;
flex-wrap: wrap;
width: 25%;
}
#selected {
border: thin solid darkgray;
border-radius: 5px;
background: lightgray;
display: flex;
align-items: center;
cursor: pointer;
height: 1.5em;
margin-bottom: .2em;
padding-left: .5em;
min-width: 150px;
position: relative;
}
#selected:after {
font-family: FontAwesome;
content: "\f0d7";
margin-left: 1em;
position: absolute;
right: .5em;
}
#options {
display: none;
margin: 0;
padding: 0;
}
#options.open {
display: inline-block;
}
li {
display: flex;
justify-content: flex-start;
align-items: center;
cursor: pointer;
width: 500px;
}
li:hover {
background-color: yellow;
}
li>img {
margin-right: 1em;
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" />
<form>
<input type="hidden" id="sel">
<div class="container">
<div id="selected">Select PickUp Point</div>
<ul id="options">
<li class="option"><span>Bccnew-01-62,Room - Bereich coupan Site university,Mooswalgfr ghytdallee 1, FREIBBNHRYURG, , 7900090, Pickup Timings - Mo-Fr: 09:00-12:00 and 13:00-16:00</span></li>
</ul>
</div>
</form>
You cannot directly wrap text in a select box option. However, you can simulate this effect by using a combination of CSS and JavaScript.
First, you will need to set the select box width:
<select style="width:200px;">
Then, you will need to apply a style to the option so that the text wraps:
<option style="white-space:normal;">
Finally, you will need to use JavaScript to detect when the option is selected and dynamically adjust the select box width based on the length of the text:
$('select').on('change', function(){ $(this).css('width', this.value.length * 10); });

How can I disable my submit button when a text area is left blank?

I am trying to make a submit button that is disabled when a text area is left blank, but alas I am not seeing results. If any advice could be spared it would be greatly appreciated. Here is the code that pertains to this problem. This submit button works as if it were not disabled, so I'm guessing there must be something wrong in my typescript or the way that I am constructing the disable in the first place, but I am getting to the point where I am running out of Ideas. If anyone has any questions feel free to ask.
<template>
<div id="editEntryDiv">
<div id="mainContent" v-if="loaded">
<PartsForm v-model="localPartEntry" />
</div>
<Teleport to="#mainContent">
<div class="actionBar">
<!-- Empty Div Required for formatting -->
<div>
<button id="deleteButton" #click="deleteItem(parseInt(id))">
<i class="fas fa-trash"></i>
<span>Delete</span>
</button>
</div>
<!-- Empty Div Required for formatting -->
<div>
<button
id="submitButton"
:class="{ disabled: localPartEntry.partNumber == undefined }"
:disabled="localPartEntry.partNumber == undefined"
#click="submitItem"
>
<i class="fas fa-paper-plane"></i>
<span>Submit</span>
</button>
</div>
</div>
</Teleport>
</div>
</template>
here is the typescript:
<script lang="ts">
import { defineComponent } from "vue";
import { usePartStore } from "../stores/part-store";
import PartsForm from "../components/PartsForm.vue";
import { PartDefinition } from "../types/PartDefinition";
import { mapStores } from 'pinia'
export default defineComponent({
components: {
PartsForm,
},
data() {
return {
loaded: false,
localPartEntry: {} as PartDefinition,
};
},
watch: {
localPartEntry: {
handler() {
if (!this.loaded) return
sessionStorage.setItem("unsavedPart", JSON.stringify(this.localPartEntry))
},
deep: true
}
},
computed: {
...mapStores(usePartStore),
id(): string {
return this.$route.params.id.toString();
},
},
methods: {
async submitItem(): Promise<void> {
this.localPartEntry.id = parseInt(this.id);
if (await this.partStore.editPartDefinition(this.localPartEntry))
if (await this.partStore.getParts())
this.$router.push({
path: `/`,
});
},
async deleteItem(id: number) {
if (confirm("Are you sure you want to delete this entry?"))
if (await this.partStore.deletePartDefinition(id))
if (await this.partStore.getParts())
this.$router.push({
path: `/`,
});
},
},
mounted() {
for (let element of this.partStore.partEntries as PartDefinition[]) {
if (element.id == parseInt(this.$route.params.id.toString())) {
this.localPartEntry.id = element.id;
this.localPartEntry.partNumber = element.partNumber;
this.localPartEntry.variant = element.variant;
this.localPartEntry.revision = element.revision;
this.localPartEntry.description = element.description;
this.localPartEntry.supplier = element.supplier;
this.localPartEntry.previewImagePath = element.previewImagePath;
this.localPartEntry.previewImageDateTime = element.previewImageDateTime;
this.localPartEntry.obsolete = element.obsolete;
this.localPartEntry.internalOnly = element.internalOnly;
this.loaded = true;
break;
}
}
},
});
</script>
And finally, the css:
<style lang="sass" scoped>
#editEntryDiv
width: 100%
height: 100%
background: $primary-background
display: flex
flex-direction: column
overflow-y: auto
-ms-overflow-style: none // for Internet Explorer, Edge */
scrollbar-width: none // for Firefox */
&::-webkit-scrollbar
display: none // for Chrome, Safari, and Opera */
#mainContent
margin-top: 1rem
margin-bottom: 5rem
flex-grow: 1
#submitButton
border: 1px solid $primary-accent-color
font-size: 1.5rem
border-radius: .25rem
cursor: pointer
padding: .25rem .75rem
transition: background .3s, color .3s
color: $primary-accent-color
background: transparent
display: flex
flex-direction: row
justify-content: center
align-items: center
gap: .5rem
&:hover
color: $tertiary-background
background: $primary-accent-color
.disabled
background: grey !important
#deleteButton
border: 1px solid $primary-accent-color
font-size: 1.5rem
border-radius: .25rem
cursor: pointer
padding: .25rem .75rem
transition: background .3s, color .3s
color: $primary-accent-color
background: transparent
display: flex
flex-direction: row
justify-content: center
align-items: center
gap: .5rem
&:hover
color: $tertiary-background
background: $primary-accent-color
.actionBar
width: 100%
min-height: 4rem !important
background: $secondary-background
display: flex
justify-content: space-between
position: fixed
bottom: 0px
right: 0px
&>div
display: flex
flex-direction: row
align-items: center
gap: 1rem
margin: 0 1rem
</style>
You can just check with Logical NOT (!) operator which takes truth to falsity and vice versa. Hence, If there will be no value in the textarea it will return false else true.
Working Demo :
new Vue({
el: '#app',
data: {
content: ''
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
Textarea content: {{ content }}
<br><br>
<textarea v-model="content"></textarea>
<button id="submitButton" :disabled="!content.trim()">
<span>Submit</span>
</button>
</div>
I just added an example to show you how to achieve. You can made the changes in your original code.

how to have a dropdown activate when input is focused?

I'm trying to make a reddit clone MERN and need a dropdown like the dorpdown in the reddit search bar
the styling is not an issue the issue is to make the dropdown appear when the input bar is focused
also i am using tailwindcss
can anyone please tell me how to do this?
I suppose you want to show the select not just when you focus the input but also when you are interacting with the select: you may avoid JS at all and use the :focus-within pseudoclass
.dropdown select {
display: none;
}
.dropdown:focus-within select {
display: block;
}
<div class="dropdown">
<input />
<select>
<option>option</option>
</select>
</div>
but if you need this to be working only on input focus
.dropdown select {
display: none;
}
.dropdown input:focus + select {
display: block;
}
<div class="dropdown">
<input />
<select>
<option>option</option>
</select>
</div>
const show = () => {
document.querySelector('.content').classList.add("active")
}
const hide = () => {
document.querySelector('.content').classList.remove("active")
}
.dropdown{
display: flex;
flex-direction: column;
position: relative;
width: 200px;
}
input{
width: 100%;
}
.content{
background: red;
padding: 4px;
position: absolute;
top: 100%;
width: 100%;
display: none;
}
.active{
display: flex;
}
<div class = "dropdown">
<input onFocus = "show()" onBlur = "hide()" />
<div class = "content">
Dropdown
</div>
</div>
React and Tailwind
const Dropdown = () => {
const [isFocus, setIsFocus] = React.useState(false);
return (
<div className = "w-40 border m-4">
<input
className = "w-full"
onFocus={() => setIsFocus(true)}
onBlur={() => setIsFocus(false)}
/>
{ isFocus && <div className = "bg-red-300">Dropdown</div>}
</div>
);
};

Dropdown vanishes as soon as it comes out of hover

I've made a list of categories in the navbar and in these categories. I want to show a dropdown just like a Flipkart website. But when I'm hovering over my categories it shows dropdown but as soon as I move my mouse over the dropdown list my dropdown vanishes.
I'm getting these categories and dropdowns from backend in the form of an array that's why I use ngFor in my Html file to display my categories and dropdown list. Is there any way to expand the hover area over the categories.
My main aim is when I mouse over my dropdown it shows till my mouse is over my dropdown and vanishes after I remove my mouse from the dropdown list.
The categories that I'm getting from backend in the form of an array are
Men
Home&Furniture
Electronics
The dropdown I am getting for these categories-
For Men-Shoes, Watches
For Electronics - Smartwatches, Laptops
home.component.html File
<div class="col-7">
<ul class="row list">
<ng-container *ngFor='let item of menus'>
<li class="px-3 Menu" (mouseover)='overMenu(item.name)'
(mouseout)='leaveMenu(item.name)' >{{item.name}}
<img class="caret ml-1" src="../../../assets/angle-arrow-down.png">
<div class="sub-menu">
<ul class="list2" *ngIf="item.name === 'Men' && flag">
<ng-container *ngFor='let i of arr'>
<li class="text-center">{{i.mensubcat}}</li>
</ng-container>
</ul>
<ul class="list2" *ngIf="item.name === 'Home&Furniture' && flag2">
<ng-container *ngFor='let i of arr'>
<li class="text-center">{{i.mensubcat}}</li>
</ng-container>
</ul>
<ul class="list2" *ngIf="item.name === 'Electronics' && flag2">
<ng-container *ngFor='let i of arr'>
<li class="text-center">{{i.esubcat}}</li>
</ng-container>
</ul>
</div>
</li>
</ng-container>
</ul>
</div>
home.component.css File
.list {
display: flex;
list-style: none;
justify-content: flex-start;
align-items: center;
position: relative;
}
.Menu
{
padding: 9px 20px;
}
.Menu:hover
{
color: rgb(9, 128, 240);
}
.Menu:hover > .caret {
color: rgb(9, 128, 240);
transform: rotate(180deg);
transition: 0.2s;
}
.list2 {
list-style: none;
position: absolute;
line-height: 37px;
display: block;
z-index: 4;
padding: 10px;
background-color: #e1e2e5e3;
border-radius: 5px;
width: 20%;
color:black;
/* padding-left: 0; */
}
home.component.ts File
overMenu(name){
if(name === "Men"){
this.flag = true
}
else if(name === 'Electronics'){
this.flag2 = true
}
}
leaveMenu(name) {
if(name === 'Men'){
this.flag = false
}
else if(name === 'Electronics'){
this.flag2 = false
}
}
I tried with mouseleave instead of mouseout and it did work.
here is the stackblitz i tried

CSS animated slide down when lower element gets removed (elements in container with relative position)

I've got a script which create a simple container for error message boxes and if needed create these boxes in it. The container got a fixed width, like the boxes but not a fixed height, so the boxes stack about each other in a vertical row. Also the boxes in the container got position: relative.
Picture of the container & boxes:
Now what I want is, that if you remove a box, the above boxes slides down, animated. I tried it with CSS transitions but it didn't work (I'm pretty new to transitions, so I don't even know if it's possible with position: relative because the top and bottom properties aren't set).
Example [See picture for reference]: I click on box 3, box 3 gets removed, box 1 and 2 slide down next to 4, 5, and 6. This works, but it isn't animated yet.
Question: Is it possible to do this with CSS, and if so, how?
HTML:
<div class="popBoxContainer popBoxContainerRight">
<div class="popBox error" onclick="this.parentNode.removeChild(this);" title="click to close">
<p class="popBox__title">error</p>
<span class="popBox__msg">Test-Box-1</span>
</div>
<div class="popBox error" onclick="this.parentNode.removeChild(this);" title="click to close">
<p class="popBox__title">error</p>
<span class="popBox__msg">Test-Box-2</span>
</div>
<div class="popBox error" onclick="this.parentNode.removeChild(this);" title="click to close">
<p class="popBox__title">error</p>
<span class="popBox__msg">Test-Box-3</span>
</div>
</div>
CSS:
.popBoxContainer {
position: fixed;
width: 300px;
bottom: 0;
padding: 0 10px 15px 10px;
}
.popBoxContainerRight {
right: 0;
}
.popBoxContainerLeft {
left: 0;
}
.popBox {
padding: 15px 25px;
margin-top: 20px;
background-color: #fff;
box-shadow: 2px 2px 3px rgba(0,0,0,.03);
opacity: 0.8;
}
.popBox:hover {
opacity: 1;
cursor: pointer;
}
.popBox .popBox__title {
font-family: 'Oswald', sans-serif;
font-size: 18px;
margin-bottom: 8px;
text-transform: uppercase;
}
.popBox.error .popBox__title {
color: #FF5252;
}
.popBox.warning .popBox__title {
color: #FFDB70;
}
.popBox .popBox__msg {
color: #4c4c4c;
}
JS:
function initPopBox(side) {
if(document.getElementsByClassName('popBoxContainer').length < 1) {
var box = document.createElement('div');
box.className = 'popBoxContainer';
if(side != "") {
if(side == "left") {
box.className += ' popBoxContainerLeft';
} else {
box.className += ' popBoxContainerRight';
}
} else {
box.className += ' popBoxContainerRight';
}
document.body.appendChild(box);
}
}
function popBox(type, txt) {
var boxCon = document.getElementsByClassName('popBoxContainer');
if(boxCon.length < 1) {
initPopBox();
}
switch(type) {
case 'error':
boxCon[0].innerHTML += '<div class="popBox error" onclick="this.parentNode.removeChild(this);" title="click to close"><p class="popBox__title">error</p><span class="popBox__msg">'+txt+'</span></div>';
break;
case 'warning':
boxCon[0].innerHTML += '<div class="popBox warning" onclick="this.parentNode.removeChild(this);" title="click to close"><p class="popBox__title">warning</p><span class="popBox__msg">'+txt+'</span></div>';
break;
default:
boxCon[0].innerHTML += '<div class="popBox error" onclick="this.parentNode.removeChild(this);" title="click to close"><p class="popBox__title">error</p><span class="popBox__msg">'+txt+'</span></div>';
break;
}
}
Without knowing your HTML it's hard to really solve. That being said, you can't get the desired behavior using only CSS, like Paulie_D said in the comments above. You can get close (if you don't need a sliding animation).
Here is a combination of CSS and jQuery that does what you want:
$("label").click(function() {
$(this).delay(600).queue(function (next) {
$(this).css('display', 'none');
next();
});
});
body {
margin: 0;
}
input[type="checkbox"] {
position: absolute;
left: -9999px;
}
.container {
width: 235px;
margin: 0 auto;
background: lightgrey;
padding: 1px 0;
}
label {
display: block;
background: white;
margin: 16px;
width: 200px;
height: 50px;
color: #c95959;
position: relative;
}
p {
margin-top: 12px;
color: #3e3b3b;
}
#box1:checked ~ .container .label1, #box2:checked ~ .container .label2, #box3:checked ~ .container .label3, #box4:checked ~ .container .label4, #box5:checked ~ .container .label5, #box6:checked ~ .container .label6 {
opacity: 0;
transition: opacity 0.7s;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<input type="checkbox" id="box1"/>
<input type="checkbox" id="box2"/>
<input type="checkbox" id="box3"/>
<input type="checkbox" id="box4"/>
<input type="checkbox" id="box5"/>
<input type="checkbox" id="box6"/>
<div class="container">
<label class="label1" for="box1">
<span>ERROR</span>
<p>Test-Error-Box-1</p>
</label>
<label class="label2" for="box2">
<span>ERROR</span>
<p>Test-Error-Box-2</p>
</label>
<label class="label3" for="box3">
<span>ERROR</span>
<p>Test-Error-Box-3</p>
</label>
<label class="label4" for="box4">
<span>ERROR</span>
<p>Test-Error-Box-4</p>
</label>
<label class="label5" for="box5">
<span>ERROR</span>
<p>Test-Error-Box-5</p>
</label>
<label class="label6" for="box6">
<span>ERROR</span>
<p>Test-Error-Box-6</p>
</label>
</div>
JSFIDDLE Example
You need to use max-height here. On the original element have a max-height of whatever height you want it to be. Using height auto I don't think will work with this. There's a good example at: http://codepen.io/LFeh/pen/ICkwe
Take a look at this code:
.element{
-webskit-transition: max-height 1s;
max-height:0px;
}
.parentelement:hover childelement {
max-height:50px;
}