vue.js - Change text based on default/clicked class - vue.js

Given the following:
<div id="#my-container">
<div class="title">Companies</div>
<div class="tab active tab-apple">Apple</div>
<div class="tab tab-google">Google</div>
</div>
When page is loaded without any tab clicks yet, whichever tab with the default active class, needs to go in the .title div. For the example above, <div class="title">Apple</div>
On click of a tab, the class is switched to active, and vue.js needs to update the .title div once again.
How can this be done with vue.js? I've tried but not able to get it to work as intended.

The answer by David is one way to do it. But Vuejs offers in-line computations for this. So, no need to hook into any CSS event. Here's some code to explain:
Create a data property active_tab, just like David mentioned. And then bind it's value just like he's done it. In your tabs, add an click event and at that event, assign appropriate value to active_tab.
<div class="tab active tab-apple" #click="active_tab = Apple">Apple</div>
<div class="tab tab-google" #click="active_tab = Google">Google</div>
Now, to dynamically assign the active class to the respective tab, make the class attribute, a computed property, like this:
<div
:class="['tab', active_tab == 'Apple' ? 'active' : '', 'tab-apple']"
>
Apple
</div>
What this code is basically doing is, :class makes class a computed property. Then the commas in the array divide the statement. So, the computation will always add tab and tab-apple classes. But, only if active_tab == 'Apple' then ? add 'active' else : add ''

Not sure which CSS framework you are using, but normally I hook into the events thrown by the tab switching (many CSS frameworks provide this access). Once hooked into it, you can write a Vue custom directive that will take that event and use it to update a VM attribute that indicates which tab is active.
Then you can use normal mustache templating to get it into your template:
<div class="title">{{ active_tab }}</div>

Related

v-else is getting rendered first instead v-if in Vue JS

I have an HTML element like below
<div v-if="showOriginalContent"> original content</div>
<div v-else> default content </div>
initial value of showOriginalContent is false
and from mounted method am calling an another method where i will make the value of showOriginalContent to true based on some conditions . Currently even if the showOriginalContent is true i can see that v-else is getting displayed for a fraction of seconds before v-if is rendered in the DOM . How can i solve this issue ? I tried to move the function call to all other life cycle methods but nothing is working . I have gone through before and after navigation approach in vue js ,Is it possible to apply that logic here?
I think it's normal if I understood correctly what you posed as the problem.
Because the mounted state is called when the view has already been OK and displayed and only once.
So a variable declaring in this method its change will not necessarily have an effect on what should be displayed.
Try to see the lifecycle in Vuejs for more detail.
Put it in computed or watch methods to see.
Use an outer div and control this div with another variable that will be true when you are done with your condition parts in mounted hook.. like this..
<div v-if="conditioncheckdone">
<div v-if="showOriginalContent"> original content</div>
<div v-else> default content </div>
</div>
It will resolve your issue of displaying v-else stuff while you are checking your conditions in mounted
turn the default showOriginalContent value to null instead of false

Using dynamic IDs in a string in a VueJS

I'm using a UIKit library for a tab component that listens to a uk-tab property that targets an id. The problem with this, is that it creates the same ID for every tabbed component. I like the UI, but whoever thought of this, didn't think too far into it. I could fix it by making the id dynamic but I am having trouble calling it in the uk-tab property because it is rendering a string. Coming from a react background, I would do a string literal and some JSX, something like #item-${_id}to show #item-12, #item-13....and so on. But That's not working. How can I do this in Vue?
Here is an example of how it works
<div class="mytrigger">
<ul uk-tab="connect: #component-tab-left; animation: uk-animation-fade">
</div>
<div class="mytargetedtab">
<ul id="component-tab-left" class="uk-switcher">
</div>
Here is an example of how what I need
<div class="mytrigger">
<ul uk-tab="connect: #_uid+'switcher'; animation: uk-animation-fade">
</div>
<div class="mytargetedtab">
<ul :id="_uid+'switcher'" class="uk-switcher">
</div>
Check out the dev tools. It should be 810switcher, but instead is taking it as a string
Any ideas? Thanks
I believe what you need is:
<ul :uk-tab="`connect: #${_uid}switcher; animation: uk-animation-fade`">
Or if you prefer not to use backticks:
<ul :uk-tab="'connect: #' + _uid + 'switcher; animation: uk-animation-fade'">
The output will be:
<ul uk-tab="connect: #22switcher; animation: uk-animation-fade">
A few notes:
Using a : is short for v-bind: but don't let the name confuse you. v-bind doesn't necessarily bind anything, it just makes the attribute value a JavaScript expression.
I'd avoid using numbers at the start of element ids, I've seen that cause problems in the past. It'd be better to put the numbers at the end.
The underscore at the start of _uid indicates that it's private to Vue. There are no guarantees about what form it will take or whether it will even exist going forward.
Use data-uk-tab instead of uk-tab like below.
<div class="mytrigger">
<ul data-uk-tab="{connect: `#${_uid}switcher`, animation: 'uk-animation-fade'}">
</div>
<div class="mytargetedtab">
<ul :id="_uid+'switcher'" class="uk-switcher">
</div>
For more information => Switcher with tabs
You can use any javascript expression in a data binding in vue. So, if you bind a string template to the attribute, it'll populate what you expect.
<ul :uk-tab="`connect: #${uid}switcher`'; animation: uk-animation-fade">

DebugElement.query does not work with elements added dynamically to the dom in a spec

I have an app that is using ngx-bootstrap to show a tooltip on mouseover. I want to test that the content, which is dynamically added, shows properly. In order to do this I have a test that looks like this:
it(shows the right tooltip', fakeAsync(() => {
fixture.debugElement.query(By.directive(TooltipDirective))
.triggerEventHandler('mouseover', null);
tick();
fixture.detectChanges();
expect(fixture.debugElement.query(By.css('.tooltip-inner')).nativeElement)
.toBe('the tooltip text');
}
This results in an error that indicates that fixture.debugElement.query(By.css('.tooltip-inner')): "Cannot read property 'nativeElement' of null"
If I print out the content of fixture.debugElement.nativeElement I get this:
<div id="root1" ng-version="5.2.9">
<my-component>
<div ng-reflect-tooltip="the tooltip text">
<img src="images/test.png">
</div>
<bs-tooltip-container role="tooltip" class="tooltip in tooltip-right">
<div class="tooltip-arrow arrow"></div>
<div class="tooltip-inner">the tooltip text</div>
</bs-tooltip-container>
<my-component>
</div>
The important take away is that the html exists - it is just not accessible by the DebugElement.query.
My current solution to get the spec passing is to change the expect to:
expect(fixture.debugElement.nativeElement.textContent.trim())
.toBe('the tooltip text');
This works, but it is a hack that will fall to pieces if I run into a similar situation with multiple tooltips (for example). Has anyone been able to handle this in a better way? Am I not setting this spec up correctly?

access local variable within *ngIf

I have a primeng (angular 2) dialog with a dropdown. I want to set focus to the dropdown when the dialog shows. The problem appears to be that my div is rendered conditionally.
My code:
<p-dialog (onShow)="fe.applyFocus()">
<div *ngIf="selectedItem">
<button pButton type="button" (click)="fe.applyFocus()" label="Focus"></button>
<p-dropdown #fe id="reason" [options]="reasonSelects" [(ngModel)]="selectedReason" ></p-dropdown>
</div>
</p-dialog>
In this code the button works fine, but the onShow() (outside the *ngIf div) tells me fe is undefined.
How can I access the local variable inside the *ngIf?
Yes, this is a real pain. Unfortunately, due to the way *ngIf works, it completely encapsulates everything inside (including the tag it's on).
This means anything declared on, or inside, the tag with the ngIf will not be "visible" outside of the ngIf.
And you can't even simply put a #ViewChild in the ts, because on first run it might not be present... So there are 2 known solutions to this problem...
a) You can use #ViewChildren. This will give you a QueryList that you can subscribe to, which will fire off every time the tempalte variable changes (ie. the ngIf turns on or off).
(html template)
<div>{{thing.stuff}}</div>
<my-component #thing></my-component>
(ts code)
#ViewChildren('thing') thingQ: QueryList<MyComponent>;
thing: MyComponent;
ngAfterViewInit() {
this.doChanges();
this.thingQ.changes.subscribe(() => { this.doChanges(); });
}
doChanges() {
this.thing = this.thingQ.first;
}
b) You can use #ViewChild with a setter. This will fire the setter every time the ngIf changes.
(html template)
<div>{{thing.stuff}}</div>
<my-component #thing></my-component>
(ts code)
#ViewChild('thing') set SetThing(e: MyComponent) {
this.thing = e;
}
thing: MyComponent;
Both of these examples should give you a "thing" variable you can now use in your template, outside of the ngIf. You may want to give the ts variable a different name to the template (#) variable, in case there are clashes.
You can separate the use of template on NgIf level:
<ng-container *ngIf="selectedItem; else elseTemplate">
<p-dialog (onShow)="fe.applyFocus()">
<div>
<button pButton type="button" (click)="fe.applyFocus()" label="Focus"></button>
<p-dropdown #fe id="reason" [options]="reasonSelects" [(ngModel)]="selectedReason"></p-dropdown>
</div>
</p-dialog>
</ng-container>
<ng-template #elseTemplate>
<p-dialog>
</p-dialog>
</ng-template>

Durandal: Showing a 'LOADING...' during composition

I can easily show a loading message while the activate method is doing its thing like so:
<div data-bind="compose:ActiveVm">
<div class="text-center" style="margin : 75px">
<i class="fa fa-spinner fa-spin"></i>
</div>
</div>
However if I then update my ActiveVm property with a different viewmodel, the splash content does not show. I understand that the splash content is only designed to show on 'initial' load, but what options do I have for displaying such a message when transitioning from one viewmodel to another?
Note that this composition does not participate in routing...
Update: Related durandal issue here which might be of value to future visitors: https://github.com/BlueSpire/Durandal/issues/414
This begs for a comment of 'what have you tried?' but given that I could see the benefit of this for future users I wanted to throw in my $0.02 -
The splash displays on your screen until Durandal loads up the application and replaces the div with id="applicationHost" 's content with the shell view and the subsequent views that are loaded. If you wanted to make this a re-usable component one thing that you could do is to take that Html.Partial view that is being loaded and create your own view inside of your app folder in your Durandal project.
For example you would create a new HTML view inside of your app folder -
splashpage.html
<div class="splash">
<div class="message">
My app
</div>
<i class="icon-spinner icon-2x icon-spin active"></i>
</div>
And then compose it from your shell -
<div data-bind="if: showSplash">
<!-- ko compose: 'splashpage.html' -->
<!-- /ko -->
</div>
And in your view model you would toggle the observable showSplash whenever you want to show / hide it -
var showSplash = ko.observable(false);
var shell = {
showSplash: showSplash
};
return shell;
And you could call that from your activate methods inside your other view models like this -
define(['shell'], function (shell) {
function activate() {
shell.showSplash(true);
// do something
shell.showSplash(false);
}
});
This sounds to me like a scenario where a custom transition may be useful. When the composition mechanism switches nodes in and out of the DOM, it can use a transition.
This page, under Additional Settings>Transition (about halfway down) describes a custom transition: http://durandaljs.com/documentation/Using-Composition/