Vue-router navigation Guard - vue.js

I wanna make a router guard but I don't know why I cant.
setAuthentication ==true if part is okay but else part is not.
I want KrediForm page cant reachable only when setAuthentication is true
This code must be work but it won't work ı don't know why
Is there another way to make a router guard
IF you don't understand pls contact me
Now I have this code
<template>
<div>
<h1>Login page</h1>
<input type="text" name="username" v-model="input.username" placeholder="Username" />
<input type="password" name="password" v-model="input.password" placeholder="Password" />
<button type="button" #click="login">Login</button>
</div>
export default {
name: 'Login',
data() {
return {
input: {
username: "",
password: ""
}
}
},
methods: {
login() {
if(this.input.username == "admin" && this.input.password == "pass") {
this.$store.commit("setAuthentication", true);
this.$router.replace({ name: "KrediForm"});
// HERE WORKS FOR ME
} else {
console.log("The username or password is not correct");
}
}
}
}
main.js file
import { createApp } from 'vue';
import Vue3Autocounter from 'vue3-autocounter';
import VuePaycard from "vue-paycard";
import router from "#/router";
import Vuex from 'vuex'
import App from './App.vue';
import "#/assets/css/starter_style.css";
import "#/assets/css/main.css";
import veProgress from "vue-ellipse-progress";
const store = new Vuex.Store(
{
state: {
authenticated: false
},
mutations: {
setAuthentication(state, status) {
state.authenticated = status;
}
}
}
)
const app = createApp(App);
app.component('vue3-autocounter', Vue3Autocounter)
app.use(router);
app.use(Vuex);
app.use(veProgress);
app.use(VuePaycard);
app.use(store);
app.mount("#app");
router.js this is what trouble me the last few days
import {createRouter, createWebHistory} from "vue-router";
import store from '#/main'
const routes = [
{
name: "KrediForm",
path: "/Kredi_Form",
component: () => import("#/views/Kredi_Form"),
<!-- HERE MY ISSUE -->
beforeRouteEnter: (to, from, next) => {
if(store.state.authenticated == true) {
next({name: 'Login'});
console.log
} else {
next();
}
}
},
{
name: "DownloadSection",
path: "/DownloadSection",
component: () => import("#/views/DownloadSection")
},
{
name: "deneme",
path: "/deneme",
component: () => import("#/views/deneme"),
},
];
const router = createRouter({
routes,
history: createWebHistory()
});
// Template must be like
// router.beforeEach((to, from, next) => {
// if(loggedIn && to.path !== '/login') {
// next();
// } else {
// next('/login');
// }
// })
export default router;

first i think you are using pre-route guard wrong. keyword in here is beforeEnter and not beforeRouteEnter based on docs.
also you need to export and import properly like this:
export
export const store = ...
import
import {store} from '#/main'

this
solved my problem, copy that

Related

Nuxt3 + Pinia + VueUse -> useStorage() not working

Setup: I'm using Nuxt3 + Pinia + VueUse.
Goal:
I want to save a state of a pinia store to localstorage via VueUse: useStorage.
Problem:
For some reason no item is created in localstorage. I feel like I'm missing something here. In components I can use useStorage fine.
in stores/piniaStoreVueUse.js
import { defineStore } from 'pinia'
import { useStorage } from '#vueuse/core'
export const usePiniaStoreVueUse = defineStore('piniaStoreUseVue', {
state: () => {
return {
state: useStorage('my-state', 'empty'),
}
},
actions: {
enrollState() {
this.state = 'enroll';
},
emptyState() {
this.state = 'empty';
},
},
getters: {
}
});
in components/SampleComponentStatePiniaVueUse.vue
<script lang="ts" setup>
import { usePiniaStoreVueUse } from '~/stores/piniaStoreVueUse';
const piniaStoreVueUse = usePiniaStoreVueUse();
</script>
<template>
<div>
piniaStoreVueUse.state: {{ piniaStoreVueUse.state }}<br>
<button class="button" #click="piniaStoreVueUse.enrollState()">
enrollState
</button>
<button class="button" #click="piniaStoreVueUse.emptyState()">
clearState
</button>
</div>
</template>
<style scoped>
</style>
Live Version here
Thank you.
I found an answer to this:
Nuxt3 uses SSR by default. But since useStorage() (from VueUse) uses the browsers localstorage this can’t work.
Solution 1:
Disables SSR in your nuxt.config.js
export default defineNuxtConfig({
ssr: false,
// ... other options
})
Careful: This globally disables SSR.
Solution 2:
Wrap your component in <client-only placeholder="Loading…”>
<client-only placeholder="Loading...">
<MyComponent class="component-block"/>
</client-only>
I'd love to hear about other ways to deal with this. I feel like there should be a better way.
I'm folowed this topic two week. My resoleved use plugin pinia-plugin-persistedstate. I'm touch plugin/persistedstate.js and add persist: true, in Pinia defineStore()
First install plugin yarn add pinia-plugin-persistedstate or npm i pinia-plugin-persistedstate
#plugin/persistedstate.js
import { createNuxtPersistedState } from 'pinia-plugin-persistedstate'
export default defineNuxtPlugin(nuxtApp => {
nuxtApp.$pinia.use(createNuxtPersistedState(useCookie))
})
and
#story.js
export const useMainStore = defineStore('mainStore', {
state: () => {
return {
todos: useStorage('todos', []),
...
}
},
persist: true, #add this
getters: {...},
actions: {...}
})
I found a solution to this problem and it seems to work pretty well. I have not done extensive testing but it seems to work.
After loads of digging I came across a page in the Pinia documentation: Dealing with Composables
NOTES:
npm i -D #vueuse/nuxt #vueuse/core
My Tested Code:
//storageTestStore.js
import { defineStore, skipHydrate } from "pinia";
import { useLocalStorage } from '#vueuse/core'
export const useStorageTestStore = defineStore('storageTest', {
state: () => ({
user: useLocalStorage('pinia/auth/login', 'bob'),
}),
actions: {
setUser(user) {
this.user = user
}
},
hydrate(state, initialState) {
// in this case we can completely ignore the initial state since we
// want to read the value from the browser
state.user = useLocalStorage('pinia/auth/login', 'bob')
},
})
test.vue (~~/pages/test.vue)
<script setup>
import { ref, onMounted } from "vue";
import { useStorageTestStore } from "~~/stores/storageTestStore";
const storageTestStore = useStorageTestStore();
// create array with 10 random first names
const firstNames = [
"James",
"John",
"Robert",
"Michael",
"William",
"David",
"Richard",
"Charles",
"Joseph",
"Thomas",
];
const updateUser = () => {
storageTestStore.setUser(
firstNames[Math.floor(Math.random() * firstNames.length)]
);
};
</script>
<template>
<div class="max-w-[1152px] mx-auto">
<h1 class="text-xl">{{ storageTestStore.user }}</h1>
<button
class="text-lg bg-emerald-300 text-emerald-900 p-5 rounded-lg"
#click="updateUser()"
>
Change User
</button>
</div>
</template>
<style scoped></style>
The state fully persisted after browser reloads and navigating in the application.
you can use ref with useStorage()
import { defineStore } from 'pinia'
import { useStorage } from '#vueuse/core'
export const usePiniaStoreVueUse = defineStore('piniaStoreUseVue', {
state: () => {
return {
state: ref(useStorage('my-state', 'empty')),
}
},
actions: {
enrollState() {
this.state = 'enroll';
},
emptyState() {
this.state = 'empty';
},
},
getters: {
}
});

QUASAR: Redirection using "push" does not work

Good day. I have the following file "pages / Login.vue"
Here the form:
Simple form
<template>
<div>
<q-form #submit="btnlogin">
<q-input v-model="user" type="text" label="Usuario" />
<q-input v-model="pass" type="password" label="Contraseña" />
<q-btn color="primary" label="Ingresar" type="submit"/>
</div>
</template>
<script>
import axios from 'axios'
import { ref } from 'vue'
import { useQuasar } from 'quasar'
import router from 'src/router/index'
export default {
setup () {
const $q = useQuasar()
const user = ref(null)
const pass = ref(null)
const btnlogin = async () => {
axios.post("http://localhost:3050/loginQuest",{
uss : user.value,
pww : pass.value
})
.then(resp=>{
if(resp.data=="ERROR"){
$q.notify({
type:'negative',
message:'Datos incorrectos!'
})
}
else{
router().push({ path: '/' })
}
})
}
return {
user, pass, btnlogin
}
}
}
</script>
When the verification is successful, the address bar changes to http://localhost: 8080 but the content does not change and the Login.vue form continues to be displayed on the screen.
it sends me to the path but does not change the content, but if I refresh the page it shows the correct content
This is my router/routes.js:
const routes = [
{
path: '/',
component: () => import('layouts/MainLayout.vue'),
children: [
{ path: '', component: () => import('pages/Index.vue') },
{ path: '/form', component: () => import('pages/Form.vue') },
{ path: '/user', component: () => import('pages/Usuarios.vue') },
{ path: '/prueba', component: () => import('pages/Prueba.vue') },
{ path: '/facturas', component: () => import('pages/Facturas.vue') },
],
},
{ path: '/login', component:()=> import('pages/Login.vue')},
{ path: '/:catchAll(.*)*', component: () => import('pages/Error404.vue')}
]
export default routes
I changed the quasar.conf.js setting in the "vueRouterMode" section from hash to history. I hope you can help me, I'm stuck in it. Thank you!
Your script should look something like this:
<script>
import axios from 'axios'
import { ref } from 'vue'
import { useQuasar } from 'quasar'
import { useRoute } from 'vue-router' // <- import useRoute here
export default {
setup () {
const $q = useQuasar()
const router = useRouter()
const user = ref(null)
const pass = ref(null)
const btnlogin = async () => {
axios.post("http://localhost:3050/loginQuest",{
uss : user.value,
pww : pass.value
})
.then(resp=>{
if(resp.data=="ERROR"){
$q.notify({
type:'negative',
message:'Datos incorrectos!'
})
}
else{
router.push({ path: '/' }) // << router is an object, not a function
}
})
}
return {
user, pass, btnlogin
}
}
}
</script>
Is Posible that on you are created route on yout router.js or router/index.js a method for wraper router (if you show you router definition help to know it).
but I was a similar problem, I resolve it with:
let router: Router;
...
export default route(function ( ... ) {
if (router) {
return router;
}
....
router = createRouter({
... // your code
});
return router;
});
it require unique intanciated object router. It solve for me.

[Vue warn]: Property "myString" was accessed during render but is not defined on instance

I use version 3 of vuejs. I am trying to save the login username in my Login.vue.
As a first step, I try to save the content of an input field with the name "myString".
Unfortunately I get the error message: "[Vue warn]: Property "myString" was accessed during render but is not defined on instance.".
What am I doing wrong ?
// Login.vue (Focus Part)
<template>
{{ myString }}
<input v-model="string" type="text" name="myString">
<p>
<button #click="setString">Set String</button>
<br>
<br>
<button #click="deleteString">Delete String</button>
</p>
</template>
<script>
import router from "#/router";
export default {
name: "Login",
components: {
Field,
Form,
ErrorMessage,
},
data() {
return {
string: "",
};
},
watch: {},
methods: {
setString() {
this.$store.commit("myString", this.string);
},
deleteString() {
this.$store.commit("myString");
},
},
};
</script>
// main.js
"use strict";
//exports.__esModule = true;
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
// import { createRouter, createWebHashHistory } from "vue-router";
import { createStore } from "vuex";
import createPersistedState from 'vuex-persistedstate';
import Cookies from 'js-cookie';
import SecureLS from "secure-ls";
const ls = new SecureLS({ isCompression: false });
const store = createStore({
state() {
return {
count: 0,
string: ""
}
},
/*plugins: [createPersistedState({
storage: {
getItem: key => Cookies.get(key),
setItem: (key, value) => Cookies.set(key, value, { expires: 3, secure: true }),
removeItem: key => Cookies.remove(key)
}
})],*/
plugins: [
createPersistedState({
storage: {
getItem: key => ls.get(key),
setItem: (key, value) => ls.set(key, value),
removeItem: key => ls.remove(key)
}
})
],
mutations: {
increment(state){
state.count++;
},
decrement: state => state.count--,
myString: (state, value) => value ? (state.string = value) : (state.string = "")
},
})
const app = createApp(App)
.use(store)
.use(router)
.mount("#app")
// App.vue
<template>
<navigation />
</template>
<script>
import Navigation from "./components/Navigation";
export default {
name: "App",
components: {
Navigation,
},
};
</script>
{{ myString }} is not defined.
You could get it from Vuex with a computed property
computed: {
mySting() {
return this.$store.state.string
}
}

failed to configure axios with django rest auth to login and get auth token

I tried these codes:
src/api/auth.js
import session from "./session";
export default {
login(Username, Password) {
return session.post("/auth/login/", { Username, Password });
},
logout() {
return session.post("/auth/logout/", {});
},
createAccount(username, password1, password2, email) {
return session.post("/registration/", {
username,
password1,
password2,
email
});
},
changeAccountPassword(password1, password2) {
return session.post("/auth/password/change/", { password1, password2 });
},
sendAccountPasswordResetEmail(email) {
return session.post("/auth/password/reset/", { email });
},
resetAccountPassword(uid, token, new_password1, new_password2) {
// eslint-disable-line camelcase
return session.post("/auth/password/reset/confirm/", {
uid,
token,
new_password1,
new_password2
});
},
getAccountDetails() {
return session.get("/auth/user/");
},
updateAccountDetails(data) {
return session.patch("/auth/user/", data);
},
verifyAccountEmail(key) {
return session.post("/registration/verify-email/", { key });
}
};
src/session.js
import axios from "axios";
const CSRF_COOKIE_NAME = "csrftoken";
const CSRF_HEADER_NAME = "X-CSRFToken";
const session = axios.create({
xsrfCookieName: CSRF_COOKIE_NAME,
xsrfHeaderName: CSRF_HEADER_NAME
});
export default session;
src/store/auth.js
import auth from "../api/auth";
import session from "../api/session";
import {
LOGIN_BEGIN,
LOGIN_FAILURE,
LOGIN_SUCCESS,
LOGOUT,
REMOVE_TOKEN,
SET_TOKEN
} from "./types";
const TOKEN_STORAGE_KEY = "TOKEN_STORAGE_KEY";
const initialState = {
authenticating: false,
error: false,
token: null
};
const getters = {
isAuthenticated: state => !!state.token
};
const actions = {
login({ commit }, { username, password }) {
commit(LOGIN_BEGIN);
return auth
.login(username, password)
.then(({ data }) => commit(SET_TOKEN, data.key))
.then(() => commit(LOGIN_SUCCESS))
.catch(() => commit(LOGIN_FAILURE));
},
logout({ commit }) {
return auth
.logout()
.then(() => commit(LOGOUT))
.finally(() => commit(REMOVE_TOKEN));
},
initialize({ commit }) {
const token = localStorage.getItem(TOKEN_STORAGE_KEY);
if (token) {
commit(SET_TOKEN, token);
} else {
commit(REMOVE_TOKEN);
}
}
};
const mutations = {
[LOGIN_BEGIN](state) {
state.authenticating = true;
state.error = false;
},
[LOGIN_FAILURE](state) {
state.authenticating = false;
state.error = true;
},
[LOGIN_SUCCESS](state) {
state.authenticating = false;
state.error = false;
},
[LOGOUT](state) {
state.authenticating = false;
state.error = false;
},
[SET_TOKEN](state, token) {
localStorage.setItem(TOKEN_STORAGE_KEY, token);
session.defaults.headers.Authorization = `Token ${token}`;
state.token = token;
},
[REMOVE_TOKEN](state) {
localStorage.removeItem(TOKEN_STORAGE_KEY);
delete session.defaults.headers.Authorization;
state.token = null;
}
};
export default {
namespaced: true,
state: initialState,
getters,
actions,
mutations
};
src/views/Login.vue
<template>
<div>
<form class="login" #submit.prevent="login">
<h1>Sign in</h1>
<label>Username</label>
<input required v-model="Username" type="text" placeholder="Name" />
<label>Password</label>
<input
required
v-model="Password"
type="password"
placeholder="Password"
/>
<hr />
<button type="submit">Login</button>
</form>
</div>
</template>
<script>
import axios from "axios";
export default {
data() {
return {
Username: "",
Password: ""
};
},
methods: {
/*login() {
let Username = this.Username;
let Password = this.Password;
this.$store
.dispatch("auth/login", { Username, Password })
.then(() => this.$router.push("/"))
.catch(err => console.log(err));*/
login({ Username, Password }) {
const API_URL = "http://127.0.0.1:8000";
const url = `${API_URL}/auth/login/`;
return axios
.post(url, { Username, Password })
.then(() => this.$router.push("/"))
.catch(err => console.log(err));
}
},
mounted() {
this.login();
}
};
</script>
first, I tried using the auth service but the failure was OPTIONS not POST.
then i used axios directly to post user and get token, but then the failure was method not allowed, I do not know what is the hidden process, can you explain please?
app.vue
<template>
<div id="app">
<navbar v-if="isAuthenticated"></navbar>
<router-view></router-view>
</div>
</template>
<script>
import { mapGetters } from "vuex";
import Navbar from "./components/Navbar";
export default {
name: "app",
components: {
Navbar
},
computed: mapGetters("auth", ["isAuthenticated"])
};
</script>
router.js
import Vue from "vue";
import Router from "vue-router";
import About from "./views/About";
import Home from "./views/Home";
import Login from "./views/Login";
import Lost from "./views/Lost";
import PasswordReset from "./views/PasswordReset";
import PasswordResetConfirm from "./views/PasswordResetConfirm";
import Register from "./views/Register";
import VerifyEmail from "./views/VerifyEmail";
import store from "./store/index";
const requireAuthenticated = (to, from, next) => {
store.dispatch("auth/initialize").then(() => {
if (!store.getters["auth/isAuthenticated"]) {
next("/login");
} else {
next();
}
});
};
const requireUnauthenticated = (to, from, next) => {
store.dispatch("auth/initialize").then(() => {
if (store.getters["auth/isAuthenticated"]) {
next("/home");
} else {
next();
}
});
};
const redirectLogout = (to, from, next) => {
store.dispatch("auth/logout").then(() => next("/login"));
};
Vue.use(Router);
export default new Router({
saveScrollPosition: true,
routes: [
{
path: "/",
redirect: "/home"
},
{
path: "/about",
component: About,
beforeEnter: requireAuthenticated
},
{
path: "/home",
component: Home,
beforeEnter: requireAuthenticated
},
{
path: "/password_reset",
component: PasswordReset
},
{
path: "/password_reset/:uid/:token",
component: PasswordResetConfirm
},
{
path: "/register",
component: Register
},
{
path: "/register/:key",
component: VerifyEmail
},
{
path: "/login",
component: Login,
beforeEnter: requireUnauthenticated
},
{
path: "/logout",
beforeEnter: redirectLogout
},
{
path: "*",
component: Lost
}
]
});
main.js
import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store/index";
import axios from "axios";
import Axios from "axios";
import VueAxios from "vue-axios";
import Vuex from "vuex";
Vue.use(Vuex);
Vue.use(VueAxios, axios);
//Vue.config.productionTip = false;
Vue.prototype.$http = Axios;
const token = localStorage.getItem("token");
if (token) {
Vue.prototype.$http.defaults.headers.common["Authorization"] = token;
}
new Vue({
router,
store,
render: h => h(App)
}).$mount("#app");
references:
https://www.techiediaries.com/vue-axios-tutorial/
https://scotch.io/tutorials/handling-authentication-in-vue-using-vuex
https://github.com/jakemcdermott/vue-django-rest-auth
Most likely CORS issues.
If you're serving the vue server on different port then the django server, then you need to set the proper CORS settings.
Please refer to https://github.com/ottoyiu/django-cors-headers/
while it seems my code is little ugly because I mixed bunch of repositories, but at least I made it make POST successfully. I used
npm install qs
then import it, then:
var username = payload.credential.username;
var password = payload.credential.password;
then editing
axios.post(url, qs.stringify({ username, password })
and it worked.

vue.js Data Pre-Fetching Problems

I'm building an app following guide https://ssr.vuejs.org/en/data.html.
So i have structure:
server.js
const express = require('express');
const server = express();
const fs = require('fs');
const path = require('path');
const bundle = require('./dist/server.bundle.js');
const renderer = require('vue-server-renderer').createRenderer({
template: fs.readFileSync('./index.html', 'utf-8')
});
server.get('*', (req, res) => {
bundle.default({url: req.url}).then((app) => {
const context = {
title: app.$options.router.history.current.meta.title
};
renderer.renderToString(app, context, function (err, html) {
console.log(html)
if (err) {
if (err.code === 404) {
res.status(404).end('Page not found')
} else {
res.status(500).end('Internal Server Error')
}
} else if (context.title === '404') {
res.status(404).end(html)
} else {
res.end(html)
}
});
}, (err) => {
res.status(404).end('Page not found')
});
});
server.listen(8080);
store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
import axios from 'axios';
export function createStore() {
return new Vuex.Store({
state: {
articles: [
]
},
actions: {
fetchArticlesList({commit}, params) {
return axios({
method: 'post',
url: 'http://test.local/api/get-articles',
data: {
start: params.start,
limit: params.limit,
language: params.language
}
})
.then((res) => {
commit('setArticles', res.data.articles);
});
},
},
mutations: {
setArticles(state, articles) {
state.articles = articles;
}
}
})
}
router.js
import BlogEn from '../components/pages/BlogEn.vue';
import Vue from 'vue';
import Router from 'vue-router';
export function createRouter() {
return new Router({
mode: 'history',
routes: [
{
path: '/en/blog',
name: 'blogEn',
component: BlogEn,
meta: {
title: 'Blog',
language: 'en'
}
},
});
}
main.js
import Vue from 'vue'
import App from './App.vue'
import {createRouter} from './router/router.js'
import {createStore} from './store/store.js'
import {sync} from 'vuex-router-sync'
export function createApp() {
const router = createRouter();
const store = createStore();
sync(store, router);
const app = new Vue({
router,
store,
render: h => h(App)
});
return {app, router, store};
}
entry-server.js
import {createApp} from './main.js';
export default context => {
return new Promise((resolve, reject) => {
const { app, router, store } = createApp()
router.push(context.url)
router.onReady(() => {
const matchedComponents = router.getMatchedComponents()
if (!matchedComponents.length) {
return reject({ code: 404 })
}
Promise.all(matchedComponents.map(Component => {
// This code not from manual because i want load this in my content-component
if (Component.components['content-component'].asyncData) {
return Component.components['content-component'].asyncData({
store,
route: router.currentRoute
})
}
// This code from manual
// if (Component.asyncData) {
// return Component.asyncData({
// store,
// route: router.currentRoute
// })
// }
})).then(() => {
context.state = store.state
resolve(app)
}).catch(reject)
}, reject)
})
}
entry-client.js
import Vue from 'vue'
import {createApp} from './main.js';
const {app, router, store} = createApp();
if (window.__INITIAL_STATE__) {
store.replaceState(window.__INITIAL_STATE__)
}
router.onReady(() => {
router.beforeResolve((to, from, next) => {
const matched = router.getMatchedComponents(to)
const prevMatched = router.getMatchedComponents(from)
let diffed = false
const activated = matched.filter((c, i) => {
return diffed || (diffed = (prevMatched[i] !== c))
})
if (!activated.length) {
return next()
}
Promise.all(activated.map(c => {
if (c.asyncData) {
return c.asyncData({ store, route: to })
}
})).then(() => {
next()
}).catch(next)
})
app.$mount('#app')
});
Components
BlogEn.vue
<template>
<div>
<header-component></header-component>
<div class="content" id="content">
<content-component></content-component>
<div class="buffer"></div>
</div>
<footer-component></footer-component>
</div>
</template>
<script>
import Header from '../blanks/Header.vue';
import Content from '../pages/content/blog/Content.vue';
import Footer from '../blanks/Footer.vue';
export default {
data() {
return {
};
},
components: {
'header-component': Header,
'breadcrumbs-component' : Breadcrumbs,
'content-component' : Content,
'footer-component': Footer
},
};
</script>
Content.vue
<template>
<section class="blog">
<div v-for="item in articles">
<p>{{ item.title }}</p>
</div>
</section>
</template>
<script>
export default {
data() {
let obj = {
};
return obj;
},
asyncData({store, route}) {
let params = {
start: 0,
limit: 2,
language: 'ru'
};
return store.dispatch('fetchArticlesList', params);
},
computed: {
articles () {
return this.$store.state.articles;
}
}
};
</script>
When i load page /en/blog
My DOM in browser looks like
<div id="app">
<div id="content" class="content">
<!-- There is should be loop content -->
<div class="buffer"></div>
</div>
<footer></footer>
</div>
But! When i look at source code page and html that server sends to me its OK.
<div id="app">
<div id="content" class="content">
<section class="blog">
<div><p>Article Title</p></div>
<div><p>Article Title 2</p></div>
</section>
<div class="buffer"></div>
</div>
<footer></footer>
</div>
Thats not all. I have other pages in my app that i dont show here. When i move at any page and go to "/en/blog" after that DOM is ok.
What's wrong here?