I'm creating a simple app with vueJS, but I have some trouble with reactivity.
When an user connects to the app he gets a JWT, I store this JWT in my localstorage. And for verifying if a user is logged I just check the token presence.
First of all, is this a good method?
Now I'm trying to update the navbar, when the user is not logged I have 2 buttons "register" "login", when he is logged I want to have my "disconnect" button showing up and the two others disappear.
I have my navbar component with a "v-if" inside for showing or not the buttons.
Currently I have set a Boolean "isLogged" in my data(), How to make vueJS watch this data and update my component when this data updates?
<div class="navbar-item" v-if="!isLogged">
<div class="buttons">
<a #click="$router.push('/login')" class="button nav-button is-outlined">
CONNEXION
</a>
<a #click="$router.push('/register')" class="button nav-button is-outlined">
INSCRIPTION
</a>
</div>
</div>
<a #click="disconnect" class="navbar-item" v-if="isLogged">
Déconnexion
</a>
data() {
return {
isLogged: this.$jwt.hasToken()
}
}
I'd like to have my navbar updating without have to refresh the component.
Use a computed value instead data.
computed: {
isLogged() {
return this.$jwt.hasToken()
}
}
Related
I have a simple situation and I thought it will be resolved easily. But got stuck.
I have a header component. There are two situations here:
Before login, the text in header component will be "LOGIN" and it will be clickable. On click, it will take me to another external url (lets assume https://www.external.com).
After login, the same header component but text will be "LOGGED IN" and it won't be clickable.
WHAT I TRIED
HTML File (header.html)
<div class="brand pull-left" (click)="onHeaderClick()">
<div class="logo"></div>
<h1>{{headerText}}</h1>
</div>
Typescript File (header.ts)
onHeaderClick() {
debugger;
if(!this.isLoggedIn) {
window.open('https://www.external.com', '_blank');
}
}
But, its not redirecting me to the specified url and not also opening a new tab.
Its just refreshing the same page.
Can anybody please help me out with any solution and also if it can be explained why its not working.
Thanks.
You should handle the logic of if it's clickable in the Template and not in the TS-logic.
Also don't use divs for onclick events, use buttons or links (in your case this is a link!). You can focus them with the keyboard and also click them with pressing spacebar while it's focused. If you use the semantically correct tag you won't have problems opening it in a new window.
Something like this:
<ng-template #contentTemplate>
<div class="logo"></div>
<h1>{{headerText}}</h1>
</ng-template>
<div *ngIf="!loggedIn; else loggedInBlock">
<a class="brand pull-left" href="https://www.example.com" target="_blank" >
<ng-container [ngTemplateOutlet]="contentTemplate">
</ng-container>
</a>
</div>
<ng-template #loggedInBlock>
<ng-container [ngTemplateOutlet]="contentTemplate">
</ng-container>
</ng-template>
And in your .ts file you have a boolean variable named loggedIn If you are logged in this is set to true, otherwise it's set to false.
If you have the same content in both containers, you can either create it's own component for this (and then just use something like app-header-content instead of the ng-container or you use, as I did in the example above, use a template.
Check Angular documentation for other ways to implement if-else logic
We are developing one POC in which, we are displaying the list of properties and we displayed respective property details in bootstrap modal popup on click of property title.
We have following React components with the hierarchy:
1 PropertyBox
1.1 PropertyList
1.1.1 PropertyInfo
1.2 PropertyDetails in Bootstrap Modal popup HTML.
The render method of PropertyBox contains following code.
render() {
return (
<div id="property-box">
<PropertyListComponent>
<div class="modal fade" id="myModal">
<div class="modal-dialog modal-lg modal-box-large">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
</div>
<div class="modal-body modal-max-height">
{propertyDetailsElement}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</div>;
In property details component there are two bootstrap 4 tabs
1. Overview (by default active)
2. ContactUs
The issue is,
Consider I opened the property details popup by clicking the Property title, and go the Contact Us tab and closed the popup.
After that I clicked on Next property title to see its property details. In that case, popup opens, respective property details are displayed but the Contact Us tab is displayed as active.
So to solve the issue I tried to re-render the PropertyDetails component using method "componentWillReceiveProps"
class PropertyDetail extends React.Component {
constructor(props) {
super(props)
// in state we have stored the images as well as current index of image and translate value
this.state = {
property: this.props.data
}
}
componentWillReceiveProps(nextProps) {
this.setState({
property: nextProps.data
})
}
render() {return (<HTML for Proeperty Details>);
}
}
I have cross verified that whether the method "componentWillReceiveProps" is called every time when I click on PropertyTitle to open the Popup, and yes it is called every time. But issue is not solved.
I am expecting that when Property details popup is opened every time the default active tab should be the Overview tab.
Is there any solution ?
There are two ways you can achieve this.
1) when you change the property add a default function called
componentWillUnMount it will remove the component from dom and it will reset its properties
or you can use
In your component, you can call this.forceUpdate() method to force a rerender.
2) The second one is passing a key to the component whenever you change the property it will update the key passing to component so every time, so you open up a property new key, will be passed and the new component instance will be opened and you will not face this problem again
I am having some issues using Buefy and Vue. I have a simple SPA (Single Page Application), that uses vue-router. I have a dropdown that looks like this:
<b-dropdown class="user-dropdown" v-model="navigation" position="is-bottom-left">
<a class="navbar-item" slot="trigger">
<span class="tag is-rounded has-text-weight-semibold avatar">OB</span>
</a>
<div class="columns is-marginless">
<div class="column has-text-centered">
<router-link to="home">
<b-icon class="is-large is-size-4" icon="ion-ionic ion-ios-search"></b-icon>
</router-link>
</div>
<div class="column has-text-centered">
<router-link to="dashboard">
<b-icon class="is-large is-size-4" icon="ion-ionic ion-ios-contact"></b-icon>
</router-link>
</div>
</div>
</b-dropdown>
Getting the dropdown to show works fine. It also hides if I click anywhere on the page, outside of the visible dropdown.
My problem is, that I have a single page application, so when I "change" page (click a link), the dropdown is still visible when the page changes.
Example:
On below page:
www.example.com/#/home
I click on the dropdown, which opens, and then click on the dashboard link, which gives me:
www.example.com/#/dashboard
But the dropdown is still visible.
Anyone know how I can do, so the dropdown will toggle when I click on the links inside it?
Update:
I use the Vue Dev tools in Chrome, and I can see that when I click on the dropdown so it toggles to active, I see this:
name:"active-change"
type:"$emit"
source:"<BDropdown>"
payload:Array[1]
0:true
And when I click anywhere on the page, to close the dropdown, it looks like this:
name:"active-change"
type:"$emit"
source:"<BDropdown>"
payload:Array[1]
0:false
Whatever the drop-down is watching for state isn't changing, because in a SPA it's just javascript. I don't know about the specifics regarding Buefy, but you'll have to set the state variable on router load, or watch some kind of variable to tell the menu that something in another part of your app is different.
I have a bunch of li elements and when the user clicks them, it opens a more detailed view of those elements in a different component.
However, it requres TWO clicks to show the data I want to show.
When the user click ONCE the component opens up with the empty view template.
When the user clicks AGAIN it then shows the populated data.
Can I not just put this in one anchor tag that routes me to me detailed view and emits the click event in one?
Is there a preferred method or better way to do this?
<ul>
<li *ngFor="let favorite of sortedFavorites; let i= index">
<a class= 'clickMe' (click)= "openContact($event, i)" routerLink= "/details">
<div *ngIf= "favorite.isFavorite">
<img class="smallImage" onerror="this.onerror=null;this.src='User Icon Small.png';"
src={{favorite.smallImageURL}} />
<h3><img src="Favorite — True.png">{{ favorite.name }}</h3>
<br>
<p>{{ favorite.companyName }}</p>
<hr>
</div>
</a>
</li>
</ul>
EDIT: Some people are suggesting that I use reslove guards to fetch the data before it is populated, but I am only pulling this from a local JSON file and passing it between my components.
you use click event for both. navigate to details page via programmatically using the router
this.router.navigate(['path']);
whatever process do in openContact() and then redirect on the details page.
add into constructor private router: Router
I have a cross platform app built using Monaca and AngularJS.
On some screens I display a generic view, and then display certain sections based on the outcome of some calculations/lookups using ng-if and ng-include.
E.g. for the Login screen, I display a generic view, while in my controller I check whether the user has logged in before. Depending on the outcome of this lookup, I either show a Welcome message OR prompt the user to Login.
Below is a abbreviated version of the generic login view.
<div>
<ons-page>
<ons-scroller >
<!-- Show if user not logged in -->
<div ng-if="!loggedIn">
<div ng-include="'login/login-details.html'"></div>
</div>
<!-- Show if user logged in -->
<div ng-if="loggedIn">
<div ng-include="'login/login-confirmation.html'"></div>
</div>
</ons-scroller>
</ons-page>
</div>
This is working fine but the issue is that the first ng-if is always shown - even just for a second - while the controller checks if the user is logged in and then sets the value of loggedIn. So the user always sees the login prompt until the controller returns true or false on the variable loggedIn.
The boolean value for loggedIn is just defined but not initialed in the controller. It only gets initiated once the lookup has been done.
How can I stop both the ng-include s from displaying till I know which one to display?
I can create another ng-if but it seems long winded and inefficient.
I would also use the ng-show and hide the items until they are evaluated using the ng-hide class, see below:
<div class="ng-hide" ng-show="!loggedIn">
<div ng-include="'login/login-details.html'"></div>
</div>
<!-- Show if user logged in -->
<div class="ng-hide" ng-show="loggedIn">
<div ng-include="'login/login-confirmation.html'"></div>
</div>
One method you can use is if loggedIn is null or undefined until you check weather the user is logged in, you can use a strict comparison operator === for true and false like so:
<div>
<ons-page>
<ons-scroller >
<!-- Show if user not logged in -->
<div ng-if="loggedIn === false">
<div ng-include="'login/login-details.html'"></div>
</div>
<!-- Show if user logged in -->
<div ng-if="loggedIn === true">
<div ng-include="'login/login-confirmation.html'"></div>
</div>
</ons-scroller>
</ons-page>
</div>
This would ensure that neither gets displayed until the outcome of your "lookup".
Another solution to the problem, depending on your choice of routing, would be to make use of ngRoute's or ui-router's resolve property. This way you can check if the user is logged in before the view is loaded.