Amplify Vue amplify-authenticator component not displaying - vue.js

I have been using an <amplify-authenticator> component on the Home.vue view of a web application, via the HelloWorld.vue component. This was working as expected, with signedIn state monitored using store.js and Vuex.
I have now switched to routing to Home.vue or Login.vue depending on sign-in state.
However, when a signed out user correctly routes to Login.vue, the page displays as expected, minus the <amplify-authenticator> component. It is clear from the Styles that this is importing (amazonOrange is listed as a color), but for some reason the sign-in interface is no longer displaying correctly.
Login.vue
<template>
<div class="login">
<div>
<vue-headful title="Login"/>
</div>
<div>
<p>
<router-link to="/">Login</router-link> |
<router-link to="/about">About</router-link>
</p>
</div>
<div>
<p><img alt="Vue logo" src="../assets/logo.png" /></p>
</div>
<div>
<amplify-authenticator></amplify-authenticator>
</div>
</div>
</template>
<script>
import { Auth } from "aws-amplify";
import { AmplifyEventBus } from "aws-amplify-vue";
export default {
name: "Login",
props: {
msg: String
}
};
</script>
If I change amplify-authenticator to amplify-sign-in then I see a sign in interface, but this needs additional scripting to implement.
I'd like to know specifically why the Authenticator component isn't displaying, since I cannot see an obvious bug in my code.

Solved. If the user is signed in to Amazon Cognito, then the <amplify-authenticator> will not display. The problem was with a bug in the check on signedIn state, which was redirecting the user to the wrong page.

Related

Separate login component than handling component Vue.js

I am trying to code a mini application with Vue.js. I want to display the login page on the first page if the user is not logged in. Else,
if the user logged in, I want to show a dashboard or a landing page.
I tried it with app.vue.
I test with a variable that I created. It works, but when I log in, I can't get access to any other page. Is there a solution to separate the login page from the landing page?
File App.vue:
<template>
<div v-if="mvar" id="app">
<div>
<Header />
<div class="container-fluid">
<div class="row">
<Sidebar />
<Main />
</div>
</div>
</div>
<notifications />
</div>
<div v-else id="app">
<Login />
<notifications />
</div>
</template>
<script>
import Main from './components/template/TheMain.vue'
import Header from './components/template/TheHeader.vue'
import Sidebar from './components/template/TheSidebarMenu.vue'
// import Login from "./modules/authentication/AuthLogin.vue";
export default {
name: 'App',
components: {
Main,
Header,
Sidebar,
// Login,
},
data() {
return {
mvar: myVar,
}
},
}
</script>

The client-side rendered virtual DOM tree is not matching server-rendered content

Versions
nuxt: ^2.14.12
node: v14.15.4
Reproduction
Hello everyone and thank you in advance.
I have a strange issue that I don't really understand what's the problem and how to deal with it.
I have installed a fresh nuxt ssr project.
I'm getting the following warning
[Vue warn]: The client-side rendered virtual DOM tree is not matching server-rendered content. This is likely caused by incorrect HTML markup, for example nesting block-level elements inside <p>, or missing <tbody>. Bailing hydration and performing full client-side render.
I have three simple components: Form, Input, Button.
Form.vue
<template>
<form v-bind="$attrs" class="w-full" #submit.prevent="$emit('submitted')">
<div class="space-y-2 mb-4">
<slot name="fields" />
</div>
<slot name="button" />
</div>
</form>
</template>
<script>
export default {
computed: {
hasFields() {
return !!this.$slots.fields
},
},
}
</script>
Input.vue
<template>
<div class="relative w-full">
<input class="form-input block w-full" />
</div>
</template>
<script>
export default {
inheritAttrs: false,
}
</script>
Button.vue
<template>
<button
type="submit"
class="relative btn inline-flex items-center justify-center transition ease-in-out duration-150"
>
Save
</button>
</template>
<script>
export default {}
</script>
I use my components in pages/index.vue like this:
<template>
<div>
<Form>
<template #fields>
<Input />
<Input />
</template>
<template #button>
<Button />
</template>
</Form>
<Form>
<template #fields>
<Input />
<Input />
</template>
<template #button>
<Button />
</template>
</Form>
</div>
</template>
<script>
export default {}
</script>
If i use the Form component only once in the view i don't get the warning.
If i use it twice i get it.
Steps to reproduce
Reproduction link
Install a fresh nuxt ssr project.
Create the components as in the reproduction link
What is Expected?
All the components to render normally without any warnings or errors.
What is actually happening?
I get the following warning.
[Vue warn]: The client-side rendered virtual DOM tree is not matching server-rendered content. This is likely caused by incorrect HTML markup, for example nesting block-level elements inside <p>, or missing <tbody>. Bailing hydration and performing full client-side render.
Some extra notes
I know that wrapping the whole thing inside a <client-only> fixes the problem but i want to understand why is this happening in order to avoid it in future cases.
Also if I remove components: true from nuxt.config.js and import the components normally again the warning is gone.
Changing the name of the components eg Button -> TheButton won't fix the problem. You can see the reproduction here.
<script>
import Input from '~/components/Input'
import Button from '~/components/Button'
import Form from '~/components/Form'
export default {
components: { Form, Button, Input}
}
</script>
There seems to be one or more components which are not supported in "Universal" Mode, i.e. they might have code which isn't being executed correctly on server end.
Please try finding that component which you think can cause an issue and wrap that component with .
Here's the link for more information: https://nuxtjs.org/docs/2.x/features/nuxt-components#the-client-only-component

How to update properties of component for dynamic router-link in vuejs

So new to Vue and haven't found anything that specifically addresses my issue.
I have a simple Vue app using VueRouter where I am trying to generate a bracket-style sports tournament that records the outcomes of the different games in the tournament.
I need to make an asynchronous axios call to a server to get info on a specific game. I do not know how to update my component properly to get this info.
App.vue is very simple. The home page is just an overview of the bracket
<template>
<div id="app">
<div id="nav">
<router-link :to="{ name: 'bracket'}">Bracket</router-link>
</div>
<router-view />
</div>
</template>
I have a view component, Bracket.vue, and, for now, all I want this view do is provide links to the different matchups in the tourney.
I have made this work pretty well dynamically as follows:
<template>
<div class="home">
<div id="nav">
<div v-for="round in rounds" :key="round">
<router-link v-for="game in gamesPerRound" :key="matchupKey(round, game)" :to="{ name: 'matchup', params: {round: round, game: game} }">Matchup {{ round }} {{ game }}</router-link>
</div>
</div>
</div>
</template>
When link is clicked, I pull up another view component, Matchup.vue, which I would like to display certain data about the matchup. (MatchupService is an axios API instance)
I pass the round # and the game # as props via router-link. These load fine in the Matchup.vue.
However, when I try to make an asynchronous call to get the matchup data, nothing happens. the matchup property never updates, not on the link click or ever. So I either get nothing (when I use a ternary as per below) or an error if I just try to use the matchup value
Matchup.vue
<template>
<div class="matchup">
<h1>Round {{ round }}</h1>
<h2>Game {{ game }}</h2>
<h6>Team 1: {{matchup.teams ? matchup.teams[0]: 0}}</h6>
<h6>Team 2: {{matchup.teams ? matchup.teams[1] : 0}}</h6>
</div>
</template>
<script>
import MatchupService from '#/services/MatchupService.js'
export default {
props: ["round", "game"],
data() {
return {
matchup: {},
}
},
async updated() {
let matchups = await MatchupService.getMatchups()
this.matchup = matchups.data.rounds[this.round].games[this.game]
},
}
</script>
I have tried many different approaches on this: updated vs. created vs. other hooks, I've tried to update a property post-load and hook that to v-if, etc.
I am just totally stymied on this so hoping for some help.
Looks like you need to use navigation hook beforeEnter in your router.js file or you can use beforeRouteEnter hook directly in your compoennt file. (NOTICE! Using beforeRouteEnter in a component file you can't access 'this', so maybe, there is a reason to use Vuex if you want to store some data within serfing your app). There you can define/fetch/set any data before redirect user to a specific page. By this way you do any actions you want and set it before redirecting.
More about you can find here:
https://router.vuejs.org/guide/advanced/navigation-guards.html

nuxt code splitting doesn't work properly

I'm just starting with nuxtjs, i have 2 pages
-index
-map
map page has one component, which is client only
and the default layout has links to the 2 pages, just the basic setup
the production build generates code split for the vendor per page but both files loads at the first page, i can't find what am i missing.
map page
<div class="container">
<client-only>
<Map />
</client-only>
</div>
</template>
<script>
import Map from '~/components/Map.vue'
export default {
components: {
Map
}
}
</script>
<style>
</style>
index page
<template>
<div class="container">
<h1 class="h-1">test hello page index</h1>
</div>
</template>
<script>
export default {
components: {
}
}
</script>
<style>
</style>
default layout
<template>
<div>
<nuxt-link to="/">home</nuxt-link>
<nuxt-link to="/map">map</nuxt-link>
<nuxt />
</div>
</template>
<style>
</style>
This is because nuxt-link prefetches the page it is linked to when it appears inside the viewport.
It's for performance reason and should not impact the initial loading of the page, since the prefetching is done during idle time.
If you would like to verify that what you are seeing is because of the prefetching, you can disable prefetching on per link basis by adding a no-prefetch attribute to nuxt-link or configuring router in nuxt.config.js
// nuxt.config.js
export default {
router: {
prefetchLinks: false
}
}
This is done only if user is on good network connection and not using save data mode. And, since this is done in browser's idle time, I'd suggest, leave it like this. Should not hurt.

Vue $emit and #click handler behaving differently on Firefox

New to Vue and wrapping my head around the main concepts.
I currently have two separate components BodyHero.vue and SelectedHero.vue that I need to pass data from BodyHero.vue to SelectedHero.vue. Since there isn't a parent-child relationship between them I've set up a simple EventBus.
import Vue from 'vue'
export const EventBus = new Vue()
I've set up a simple emitter to pass information from BodyHero.vue to SelectedHero.vueupon click on router-link. (I'm using vue-router to route pages and the routes work appropriately - upon click the user is taken from BodyHero.vue to SelectedHero.vue.)
This is a portion of BodyHero.vue:
<template>
<div class="columns" style="margin: 0px 10px">
<div v-for="cryptoCurrency in firstFiveCryptoCurrencies" class="column">
<router-link to="/selected" #click.native="selectCryptoCurrency(cryptoCurrency)">
<div class="card">
<div class="card-image">
<figure class="image is-4by3">
<img :src="`/static/${cryptoCurrency.id}_logo.png`">
</figure>
</div>
<div class="card-content">
<p class="title is-5">{{ cryptoCurrency.name }}</p>
</div>
</div>
</router-link>
</div>
</div>
</template>
<script>
import { EventBus } from '../../event-bus.js'
const cryptoCurrencyData = require('../../cryptocurrency-data.json')
export default {
props: {},
name: 'bodyHero',
selectCryptoCurrency (cryptoCurrency) {
EventBus.$emit('cryptoCurrencySelected', cryptoCurrency)
}
And in SelectedHero.vue, upon created I listen for the emit.
created () {
EventBus.$on('cryptoCurrencySelected', cryptoCurrency => {
...
})
}
Now for the weird part. Chrome/Safari everything seems to work fine - the user is routed to the next component, the emit is successfully called and the cryptoCurrency object is appropriately passed.
For Firefox however, it appears that the EventBus.$emit('cryptoCurrencySelected', cryptoCurrency) doesn't seem to fire upon click (#click.native). So the user is directed to the next screen - and the object is empty. Not sure what's really the issue here or if I'm missing something. Would be happy to hear other opinions!