Active class not reactive on the first load using vue.js - javascript

So I am building a tab component and using :class to bind the active class like this.
<nav class="tabs__header" >
<ul>
<li>
<a
ref="tabItems"
v-for="(tabItem, idx) in tabs"
:key="tabItem.idx"
:class="{ 'b-active': idx === selectedIndex }"
#click="changeTab(idx)">
<span v-if="icon"> {{ tabIcon }} </span>
{{ tabItem.name }}
</a>
</li>
</ul>
</nav>
The selectedIndex is set with tabIndex value when mounted() for the first time and updated based on the 'idx' selected afterward. I have no problem with the b-active class if we click the tab manually, but it not bind the tabIndex value assigned in mounted().
This is the script I use to directly add value '0' for testing and still not get anything.
props: {
tabIndex: {
type: String,
default: '0'
},
mounted() { this.selectedIndex = this.tabIndex }
can anyone help me? because it seems very simple and I couldn't figure it out for 2 days

The problem solved and it turns out to be the data type problem, apparently tabIndex is a String and selectedIndex is a Number.
I changed:
:class="{ 'b-active': idx === selectedIndex }"
to:
:class="{ 'b-active': idx == selectedIndex }"
and it worked!

At initial render idx seems to be undefined.
Replace this:
:key="tabItem.idx"
With this:
:key="idx"
This now should work fine.
Alternatively, you may use v-for like:
v-for="tabItem in tabs"
Now, using tabItem.idx works just fine as you do in others like tabItem.name.
So, here's your code updated:
<nav class="tabs__header" >
<ul>
<li>
<a
ref="tabItems"
v-for="tabItem in tabs"
:key="tabItem.idx"
:class="{ 'b-active': tabItem.idx == selectedIndex }"
#click="changeTab(idx)">
<span v-if="icon"> {{ tabItem.icon }} </span>
{{ tabItem.name }}
</a>
</li>
</ul>
</nav>

Related

How to highlight the selected item from basic dropdownlist in ember?

I'm using a basic dropdown in Ember and in the list, once we select item in the content list, I want to highlight the selected item. I'd like to know if I can use a simple [aria-current] & [aria-selected] in CSS to make it happen.
hbs file:
{{#each pagelist as |page|}}
<li class=" dropdown-class" {{action "getAllPages" page dd.actions}}>
<p {{page.name}}</p>
</li>
{{/each}}
I think the quickest way to get you highlighted "Something selected", would be to,
(using ember-source 3.25+)
and: https://github.com/NullVoxPopuli/ember-functions-as-helper-polyfill/ (landing in ember-source 4.5~ish, polyfilled for 3.25+)
// app/components/my-component.js
import Component from '#glimmer/component';
import { tracked } from '#glimmer/tracking';
export default class MyComponent extends Component {
#tracked selectedIndex;
select = (index) => this.selectedIndex = index;
isSelected = (index) => this.selectedIndex === index;
}
{{!-- app/component/my-component.hbs --}}
{{!-- where does pagelist come from? - let's assume it's passed in --}}
<ul>
{{#each #pagelist as |page index|}}
<li
class="dropdown-class {{if (this.isSelected index) 'highlighted'}}"
{{on "click" (fn this.select index)}}
>
<p>{{page.name}}</p>
</li>
{{/each}}
</ul>
Note though, that it's an accessibility violation to make <li> clickable (and ember-template-lint would give you an error), so you'll probably want a button in the li instead:
<li class="dropdown-class {{if (this.isSelected index) 'highlighted'}}">
<button type="button" {{on "click" (fn this.select index)}}>
{{page.name}}
<button>
</li>

Vue class binding attribute and multiple tailwind classes

I'm trying to bind an attribute and multiple tailwind classes to an html element. This is for a tab menu, so the idea is that for the "active" tab I take the title dynamically and inject also some tailwind classes to change the look and feel of the "active" tabs.
<li
:class="{
selected: title === selectedTitle,
selected ? ['border-b-2', 'border-blue-700' ]
}"
#click.stop.prevent="selectedTitle = title"
v-for="title in tabTitles"
:key="title"
role="presentation"
>
At the moment the previous code is not working for me.
From my point of view following line can't work:
selected ? ['border-b-2', 'border-blue-700' ]
This is a short if else without an else case - I think you ment writing something like this:
<li :class="{
'selected border-b-2 border-blue-700': title === selectedTitle,
}">
Try like following:
new Vue({
el: "#demo",
data() {
return {
tabTitles: ['aaa', 'bbb', 'ccc'],
selectedTitle: ''
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.2.19/tailwind.min.css" integrity="sha512-wnea99uKIC3TJF7v4eKk4Y+lMz2Mklv18+r4na2Gn1abDRPPOeef95xTzdwGD9e6zXJBteMIhZ1+68QC5byJZw==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<div id="demo">
<li :class=" selectedTitle === title ? 'border-b-2 border-blue-700' : '' "
#click.stop.prevent="selectedTitle = title"
v-for="title in tabTitles"
:key="title"
role="presentation"
>{{title}}</li>
</div>

Target element when inside v-for loop Vuejs

I am trying to build a To-Do list in Vue.js which has 3 columns: To-Do, Doing, Done.
I would like to be able to move an item between columns by clicking on arrows that are inside the list item.
Right now I have a list of objects that I separate in 3 arrays depending on a "status" attribute. I would like to change that attribute when clicking on left/right arrow then refresh the UI with new arrays.
I haven't found the way to target the element that received the click.
<ul>
<li v-for="todo in todoTodos" v-bind:key="todo._id">
<span v-if="todo.importance == 1" class="bg-success"></span>
<span v-else-if="todo.importance == 2" class="bg-warning"></span>
<span v-else-if="todo.importance == 3" class="bg-alert"></span>
<div>
<h3>{{ todo.title }}</h3>
<p>{{ todo.description }}</p>
</div>
<p class="todo__date">Début: {{ todo.datebegin }} - Fin espérée: {{ todo.dateend }}</p>
<div class="todo__actions">
<i #click="editTodo" class="icofont-edit"></i>
<i #click="moveRight" class="icofont-arrow-right"></i>
<i #click="moveLeft" class="icofont-arrow-left"></i>
</div>
</li>
</ul>
My linter prevents me from using v-for + v-if, but I guess that means I will have to re-calculate each list (todoTodos, doingTodos, doneTodos) after each modification. Is there a better way ?
I tried console.logging this e.target e.currentTarget but
this logs the entire data model
e.target and e.currentTarget logs the element which I can't use to find my way back to the todo item I want to modify
You /usually/ pass the ($event) argument to a method if you want to access an event.
<i #click="moveLeft($event)" class="icofont-arrow-left"></i>
......
methods: {
moveLeft(e){
console.log(e.target)
}
}

How to change an angular2 html dynamically?

Im trying to find a way to change some html lines of a component dynamically.
<li *ngFor="p in persons" [attr.id]="p.id">
<span> {{ p.name }} </span>
<a (click)="getAge(p.id)">Get Age<a/>
</li>
If the user clicks on the Get Age link i would like to replace the content inside of the corresponding li tag to something like:
<span> {{ p.OtherProperty }} </span>
<a (click)="OtherMethod(p)">Call OtherMethod<a/>
I found that ComponentFactoryResolver to create dynamic components, but i found it too overwhelming for just 2 lines of html. And i tried to change it by hand using jquery but it does not work to create the event bindings:
getAge(id) {
//some work
//remove the corresponding <li> content
$('#' + id).append('<a (click)="getAnotherValue(p.name)">GetAnotherValue<a/>');
$('#' + id).append('<span> {{ p.age}} </span>'); //this obviously doesnt work. But thats the ideia.
}
So how can i replace some html tags with angular attributes dynamically?
You could access the person's Object property dynamically like this:
object[property]; // Where property is a string
// If property equals 'name', the above sentence would equal this:
object.name; // or `object['name'];`
So, following your example, you could do this:
export class App {
persons = [
{
id: 1,
name: 'John',
age: 25
},
{
id: 2,
name: 'Mike',
age: 30
}
];
selectedProperty = 'name';
constructor() {
}
getProperty(prop) {
this.selectedProperty = prop;
}
}
And in your template you could:
<div>
<li *ngFor="let p of persons" [attr.id]="p.id">
<span> {{ p[selectedProperty] }} </span>
<br>
</li>
<button (click)="getProperty('age')">Get Age</button>
<button (click)="getProperty('name')">Get Name</button>
</div>
If I understood well, this should do the trick. You can't use ngIf because if you have 60 properties or persons then will be somewhat caothic.
Check the Plunker
Use ngIf to activate the code as shown:
<li *ngFor="p in persons" [attr.id]="p.id">
<div *ngIf=!p?.touched>
<span> {{ p.name }} </span>
<a (click)="getAge(p)">Get Age<a/>
</div>
<div *ngIf=p?.touched>
<span> {{ p.age}} </span>
<a (click)="getAnotherValue(p.name)">GetAnotherValue<a/>
</div>
</li>
isGetAgeClicked=false;
getAge(person) {
//some work
//remove the corresponding <li> content
person.touched=true
}

angularjs ng-repeat hide element with a click event

There is a list of items which is displayed using ng-repeat. Each item is associated with a hide link. The intent is to hide an item if its corresponding hide link is clicked.
view:
<div ng-repeat="item in products">
<div>{{ item }}</div>
<a href"javascript:void(0)" ng-click="hideMe(item)">[delete]</label>
</div>
How could I implement the function hideMe(item) such a way that it could hide item div element, something like following, ng-if could identify when to hide based on the click event -
<div ng-if="...">{{ item }}</div>
For every list-item, you want to hide it if it's clicked. The best way we can do this is by adding the ng-hide directive.
Using the ng-click directive on a button, we can set the hidden property of an item to true, meaning it should be hidden.
<ul>
<li ng-repeat="fruit in fruits" ng-hide="fruit.hidden">
<p>{{fruit.name}}</p>
<button ng-click="hideMe(fruit)">hide li</button>
</li>
</ul>
$scope.hideMe = function (fruit) {
fruit.hidden=true;
alert('hide this li');
};
Here is a fiddle
http://jsfiddle.net/5yh8bxay/1/
You could use an array of objects like this: $scope.products = [{name: 'hello', status: true}]
And then you can hide them changing the status property:
<div ng-repeat="item in products">
<div ng-show="item.status">
{{ item.name }} <a href"javascript:void(0)" ng-click="item.status = false">[delete]</label>
</div>
</div>
JSFiddle
You can use $index to do that.
Something like this.
<div ng-repeat="item in products">
<div ng-hide="selected.index === $index">{{ item }}</div>
<a href"javascript:void(0)" ng-click="selected.index = $index">[delete]</label>
</div>
Just store the selected value when clicked and use-hide you can use ng-class to hide the item, comparing them to the selected index.

Categories

Resources