How to deal when llogged user refresh page of vuejs/vuex app? - laravel-5

in my laravel 5.8 / vuejs 2.5 / "vuex 3.1 user login into the system and some data are stored in user's store, like in auth/Login.vue:
<script>
export default {
...
mounted() {
this.setAppTitle("", 'Login', bus);
}, // mounted() {
computed: {
authError() {
return this.$store.getters.authError;
}
}, // computed: {
methods: {
authenticate() {
this.$store.dispatch('login'); // calling action
login(this.$data.form)
.then((res) => {
this.$store.commit("loginSuccess", res); // calling mutation
this.$store.dispatch('retrieveUserLists', res.user.id );
this.$router.push({path: '/websites-blogs'}); // For debugging!
})
.catch((error) => {
this.$store.commit("loginFailed", {error}); // calling mutation
});
}
}, // methods: {
and store where user's account and his data are kept resources/js/store.js :
export default {
state : {
currentLoggedUser: user,
// personal data only for logged user
userLists: [],
},
getters : {
...
userLists(state) {
return state.userLists;
},
It works ok, until logged user refresh page (F5 or CTRL+R) and user is still logged in my page, but some data, say (userLists)
are empty and some listing is empty.
I have MainApp.vue :
<template>
<body class="account-body">
<v-dialog/>
<MainHeader></MainHeader>
<div class="content p-0 m-0" style="width: 100% !important; margin: auto !important;">
<notifications group="wiznext_notification"/>
<router-view></router-view>
</div>
</body>
</template>
<script>
...
export default {
name: 'main-app',
components: {MainHeader},
mixins: [appMixin],
created() {
},
mounted() {
...
},
methods: {
...
}, // methods: {
}
</script>
and resources/views/index.blade.php :
<?php $current_dashboard_template = 'Horizontal' ?>
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title id="app_title">{{ config('app.name', 'Laravel') }}</title>
<link href="{{ asset(('css/Horizontal/bootstrap.min.css')) }}" rel="stylesheet" type="text/css">
<link href="{{ asset(('css/Horizontal/icons.css')) }}" rel="stylesheet" type="text/css">
<link href="{{ asset(('css/Horizontal/style.css')) }}" rel="stylesheet" type="text/css">
...
{{--<link href="css/Horizontal/ion.rangeSlider.css" rel="stylesheet" type="text/css"/>--}}
{{--<link href="css/Horizontal/ion.rangeSlider.skinModern.css" rel="stylesheet" type="text/css"/>--}}
{{--<link href="css/Horizontal/powerange.css" rel="stylesheet" type="text/css"/>--}}
<link href="{{ asset(('css/'.$current_dashboard_template.'/app.css')) }}" rel="stylesheet" type="text/css">
...
</head>
<body>
<div class="wrapper" id="app">
<main>
<div id="main_content">
<mainapp></mainapp>
</div>
</main>
</div>
</body>
#include('footer')
<script src="{{ asset('js/jquery.min.js') }}"></script>
<script src="{{ asset('js/bootstrap.bundle.min.js') }}"></script>
<script src="{{ asset('js/metisMenu.min.js') }}"></script>
<script src="{{ asset('js/waves.min.js') }}"></script>
<script src="{{ asset('js/jquery.slimscroll.min.js') }}"></script>
<script src="{{ asset('js/app.js') }}{{ "?dt=".time() }}"></script>
{{--<script type="text/javascript" src="{{ asset('js/vuecsv.min.js') }}"></script>--}}
</html>
Could you please to advice a proper way of such situations ? What could I do?
MODIFIED :
I tried to remake my storage and seems it works ok :
const user = getLocalUser();
export default {
state : {
currentLoggedUser: user,
isLoggedIn: !!user,
loading: false,
auth_error: null,
api_url: '/api',
// personal data only for logged user
userLists: [], // I need to save data on page refresh
},
getters : {
...
userLists(state) {
// that works ok after user logged into the system and userLists is read on all page without refresh
if ( state.userLists.length > 0 ) {
return state.userLists;
}
// if userLists is empty check data in localStorage which were saved in refreshUserLists mutation
let localStorageUserLists = JSON.parse(localStorage.getItem("userLists"));
if ( localStorageUserLists.length > 0 ) {
console.log("localStorageUserLists RETURNED::")
return localStorageUserLists;
}
return [];
},
},
mutations : {
// that works ok after user logged into the system and his personal data(in my case 5 rows) are read from db into the vuex store
refreshUserLists(state, payload) {
state.userLists = payload;
localStorage.setItem("userLists", JSON.stringify(payload) );
},
},
What else have I to pay attention at ?

So the thing is, Vuex control your data status across your entire application and components, but once your user press F5 or any other refresh option, the Vuex is reset, there is nothing you can do about it, it's just like it works.
One work around solution i can think right now is to save the data on Vuex and maybe on localstorage, then, on vuex create lifecycle you can just populate the data with the localstorage data if it's empty.

I disagree with the proposed solutions. A browser refresh usually indicates that the user wants to fetch the most fresh data from the server, and reset the app state with that fresh data. Therefore you shouldn't store Vuex state in localStorage or cookies to get around this. If you do that, you now have your app state in two places, and also the user thinks they have the most fresh data when they don't.
The best way to handle a browser refresh event in a SPA is to bootstrap your state from scratch. When your app loads after a refresh, it should notice that the user is not logged in (since that is the default state), and should log them in by negotiating with the server behind the scenes, such as by sending the session cookie and receiving confirmation (or redirecting to login page if the session has expired). It should also re-fetch all relevant data from the server and store that in Vuex again.

you can use both localStorage and cookies.due to problems that I had with LocalStorage i recommand cookies. Vue has a rich plugin called Vue-cookies.
you can set and get data by these commands:
var user = { id:1, name:'Journal',session:'25j_7Sl6xDq2Kc3ym0fmrSSk2xV2XkUkX' };
this.$cookies.set('user',user);
// print user name
console.log(this.$cookies.get('user').name)
more details:
Github

Related

How to pass logged user from control to vuejs component?

in laravel 8/2.6/bootstrap 4.6/Axios app I want to pass logged user from control to vuejs component:
public function index()
{
$loggedUser = auth()->user();
return view('chat', [
'loggedUser' => $loggedUser,
]);
}
in blade file :
#extends('layouts.app')
#section('content')
<div class="container chats">
loggedUser::{{ $loggedUser}}!!!!!!!!!
<!-- I SEE USER data above : -->
<user-rooms :loggedUser="{{ $loggedUser }}"> </user-rooms>
</div>
#endsection
and vue component :
<template>
<div class="container">
loggedUser::{{ loggedUser}}
<!-- I see empty value above outputed -->
</div>
</template>
<script>
export default {
name: "Chat",
components: {},
props: {
loggedUser : {
type: Object,
required: true,
},
},
mounted() {
console.log('UserRooms.vue Component mounted loggedUser')
console.log(this.loggedUser) // I see undefined outputed
}, // mounted() {
};
</script>
I tried several direrent cases like :
<user-rooms :loggedUser="{{ json_encode($loggedUser) }}"> </user-rooms>
but failed anyway...
Which way is correct?
Thanks!
You should follow these steps to pass auth user in vue component.
You should add a <meta name="user" content="{{ Auth::user() }}"> in
// app.blade.php or whatever you have maybe master.blade.php like below
<head>
<meta charset="UTF-8">
#if (Auth::check())
<meta name="user" content="{{ Auth::user() }}">
#endif
<meta http-equiv="X-UA-Compatible" content="IE=edge"
...
...
and then in your component inside data object do this action:
data() {
return {
loggedUser : document.querySelector("meta[name='user']").getAttribute('content')
}
},
and you should see the logged in user in component mounted method:
mounted() {
console.log(this.loggedUser);
},
and now you can use the user object in every where of your component.
You can also get logged in information with this example:
lets say app.blade.php its your file that loads your page.
You can set a script that stores your authentication.
<script>
window.user = {{!! Auth::user() !!}}
</script>
Then in your vue component or even better if you are using vuex store you can get the object.
data(){
loggedUser: window.user
}

How to keep the component alive when refreshing page VUEJS [duplicate]

I am creating a simple laravel and vuejs CRUD Application. Vue Routes are not working, I am pretty new to vuejs; please see the code
Below is the code for web.php
Route::get('/', function () {
return view('welcome');
});
Auth::routes();
Route::get('/home', 'HomeController#index')->name('home');
Route::get('/vue','Api\PostController#home');
Route::resource('/api','Api\PostController');
Following is the code for app.js
require('./bootstrap');
window.Vue = require('vue');
window.VueRouter=require('vue-router').default;
window.VueAxios=require('vue-axios').default;
window.Axios=require('axios').default;
let AppLayout = require('./components/App.vue');
const Posts = Vue.component('Posts',require('./components/Posts.vue'));
const EditPost =
Vue.component('EditPost',require('./components/EditPost.vue'));
const AddPost =
Vue.component('AddPost',require('./components/AddPost.vue'));
const DeletePost =
Vue.component('DeletePost',require('./components/AddPost.vue'));
const ViewPosts =
Vue.component('ViewPosts',require('./components/ViewPosts.vue'));
const ExampleComponent =
Vue.component('ViewPosts',require('./components/ExampleComponent.vue'));
// Registering routes
Vue.use(VueRouter,VueAxios,axios);
const routes = [
{
name: 'Posts',
path: '/posts',
component: Posts
},
{
name: 'AddPost',
path: '/add-posts',
component: AddPost
},
{
name: 'EditPost',
path: '/edit-post/:id',
component: EditPost
},
{
name: 'DeletePost',
path: '/delete-post',
component: DeletePost
},
{
name: 'ViewPosts',
path: '/view-post',
component: ViewPosts
},
{
name: 'ExampleComponent',
path: '/example-component',
component: ExampleComponent
},
];
const router = new VueRouter({mode: 'history', routes: routes});
new Vue(
Vue.util.extend(
{ router },
AppLayout
)).$mount('#app');
This is the code of my blade tamplate, when I browse http://localhost:8000/vue this view is being rendered. As you can see in the web.php code above.
I can also see the notification in console You are running Vue in development mode. Make sure to turn on production mode when deploying for production.
<!DOCTYPE html>
<html lang="{{ app()->getLocale() }}">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- CSRF Token -->
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>{{ config('app.name', 'Laravel') }}</title>
<!-- Styles -->
<link href="{{ asset('css/app.css') }}" rel="stylesheet">
</head>
<body>
<div class="container">
<header class="page-header">
<div class="branding">
<img src="https://vuejs.org/images/logo.png" alt="Logo" title="Home page" class="logo"/>
<h1>Vue.js CRUD With Laravel 5 application</h1>
</div>
</header>
</div>
<section id="app">
</section>
<script>
window.Laravel = <?php echo json_encode([
'csrfToken' => csrf_token(),
]); ?>
</script>
<script src="{{ asset('js/app.js') }}"></script>
</body>
</html>
But when I run my application using
php artisan serve
and browse to
http://localhost:8000/posts
Application show a 404 error. Please help me with this problem.
You need to add a laravel route for the view where you are using the app.js (vuejs) in routes/web.php file.
Route::get('/route-name/?{name}', function(){
return redirect('vue_app');
})->where('name', '[A-Za-z]+');
and then you have to use the laravel route as a parent route for the vuejs's routes and use the url like below,
http://localhost:8000/laravel-route/view-route
in your case,
http://localhost:8000/route-name/posts
Or you can also use,
Route::get('{any}', function () {
return view('vue_app');
})->where('any', '.*');
and instead of previous use localhost:8000/posts
Try this to your web.php route
Route::get('/', function () {
return view('index');
});
Route::get('/{catchall?}', function () {
return response()->view('index');
})->where('catchall', '(.*)');
if with {any} did not work, you may also try adding ?
Route::get('/any-your-route/{any?}', function() {
return view('your-view');
})->where('any', '.*');
hope this help you. i just try this code and work on laravel blade template with vue router.
Tested on Laravel 8
For your second part of question,
You should use <div> instead of <section> and you have to bring the main/registered component inside of the html element selected by id="app" in blade file. in your case,
<div id="app">
<app-layout></app-layout>
</div>
Hope this help you. you can check this basic vuejs with laravel
PS: You should ask two different problem in two seperate posts.
you can do simply like this.
Route::get('/{vue_capture?}', function(){
return view('welcome');
})->where('vue_capture', '[\/\w\.-]*');

Laravel class access in Vue.js

I have the following class where I defined my Minimum/Maximum length values:
class MinMaxValuesUser {
const Min_UserName = 6;
const Max_UserName = 30;
}
Below is the rule in request class where the min max values are used instead of hardcoding it.
public function messages() {
return [
"Min_UserName.min" => trans("Profile.Min_UserName"),
"Max_UserName.max" => trans("Profile.Max_UserName")
];
}
public function rules() {
return [
"UserName" => "min:" . MinMaxValuesUser::Min_UserName
. "|max:" . MinMaxValuesUser::Max_UserName
];
}
and below is the JQuery Validate code where I used the same server-side class.
$('form#frmProfile').validate({
rules: {
UserName: {
minlength: {!! \App\MinMaxValues\MinMaxValuesUser::Min_UserName !!},
maxlength: {!! \App\MinMaxValues\MinMaxValuesUser::Max_UserName !!}
}
}
});
Issue
As I am writing a lot of code, so I have started to use Vue.js which is already embedded in Laravel. Everything works great here
but as we know vue.js is a front-end framework and loads in client side so will not be able to use the above server-side classes to keep the min max numbers centralized.
Kindly suggest how to get rid of this issue.
put your user configurations in a /config/user.php file like this
<?php
return [
'Min_UserName' => 4,
'Max_UserName' => 10
];
You can now access it anywhere in your php like this
config('user.Min_userName'); // specific value
config('user'); // array of both values
And you can place it into your view files like this:
#json(config('user'))
If your view component is defined in a blade file you can put this in your data definition:
'user_requirements': #json(config('user'))
If your vue component is buried down further in a js file then you'll want to define a js variable in your blade template (probably your layout) like this
let MyUserReqs = #json('user');
And then you can define it in your vue component using the js variable MyUserReqs.
You can set up your app.blade.php template something like this:
<!DOCTYPE html>
<html lang="{{ app()->getLocale() }}">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- CSRF Token -->
<meta name="csrf-token" content="{{ csrf_token() }}">
<!-- Site Properties -->
<title>{{ config('app.name') }}</title>
<!-- Styles -->
<link href="{{ asset('inside/css/app.css') }}" rel="stylesheet">
</head>
<body>
<div id="app"></div>
<!-- Scripts -->
<script src="{{ asset('inside/js/app.js') }}"></script>
<script type="text/javascript">
const globalProps = {
minlength: {!! \App\MinMaxValues\MinMaxValuesUser::Min_UserName !!},
maxlength: {!! \App\MinMaxValues\MinMaxValuesUser::Max_UserName !!}
}
globalProps.install = function(){
Object.defineProperty(Vue.prototype, '$globalProps', {
get () { return globalProps }
})
}
Vue.use(globalProps);
</script>
</body>
</html>
We define a constant, then "install/define" that constant as a vue.prototype object, then we tell vue to use it. You can also do that set up in any blade template... but if you need it everywhere on you app, you can set it up here.
Then you are ready to go, in your vue instances you can use it like this for the html/template
<div v-if="$globalProps.minlength == 6"></div>
And if you want to access it inside the script:
methods: {
someMethod() {
if(this.$globalProps.maxlength == 6){
}
},
}
Outside vue, on jquery, you could refer to it simply as globalProps.maxlength
I would take the validation logic away form the front end and instead handle this in the backend. This way, you only have to write the validation logic in one place and the front end will handle the response appropriately.
Jeffery Way did a really good tutorial on this. I would recommend following this - https://laracasts.com/series/learn-vue-2-step-by-step/episodes/19

json print required data with ng-repat

i am new to coding and i am starting with angular js....
i have a json like below
$scope.data={
"items":
{
"yamaha":
{
"title":"R15",
"description":"sports mode",
"speed":"180kmph"
},
"Tvs":
{
"title":"apache",
"description":"sports mode",
"speed":"150kmph"
}
}
};
now my requirement is to show each value one after other in html.....
Note
As i said i am new,i have googled this and found some info like ng-repeat but i didnt understand how to use this in while implementing.
thanks for your response
ng-repeat will iterate over the data in the given array....here i used key,vakue concept to print object keys and values
<!doctype html>
<html ng-app="plunker" >
<head>
<meta charset="utf-8">
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css">
<script src="http://code.angularjs.org/1.1.4/angular.js"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<div ng-repeat="(k,v) in data.items">
<div><h2>{{k}}</h2>
<p>{{ v.title }}</p>
<p>{{v.description }}</p>
<p>{{v.speed }}</p>
</div>
</div>
</body>
<script>
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.data={
"items":
{
"yamaha":
{
"title":"R15",
"description":"sports mode",
"speed":"180kmph"
},
"Tvs":
{
"title":"apache",
"description":"sports mode",
"speed":"150kmph"
}
}
};
});
</script>
</html>

Custom Polymer component returning error: unexpected token . base.js:164

I'm prototyping a Polymer-based front end for a clean RESTful services layer. I think I've got the component-level AJAX working, but it's not painting to the Shadow DOM...instead, I'm getting an error in Chrome: Uncaught SyntaxError: Unexpected token . from base.js:164 (root.appendChild(dom)).
My code:
<link rel="import" href="/bower_components/polymer/polymer.html">
<link rel="import" href="/bower_components/core-ajax/core-ajax.html">
<polymer-element name="feed-posts">
<template>
<link rel="stylesheet" href="/assets/css/bootstrap.min.css">
<link rel="stylesheet" href="/assets/css/styles.css">
<core-ajax id="stream" url="https://api.myhost.com/1/streams" handleAs="json" params=" {{ streamparams }}" auto on-core-response="{{ feedLoaded }}"></core-ajax>
<template repeat="{{f in feed }}">
<div class="tile">
<div class="heroTop">
<div class="headline">Post ID is {{ f }}</div>
</div>
</div>
</template>
<script>
Polymer('#stream', {
accesstoken: document.querySelector('app-globals').accesstoken,
userid: document.querySelector('app-globals').userid,
streamparams: { "access_token": this.accesstoken, "user_id": this.userid }
});
</script>
</template>
<script>
Polymer('newsfeed-posts', {
created: function(){
this.feed = [];
},
feedLoaded: function(){
this.feed = this.$.stream.response['post_ids'];
}
});
</script>
</polymer-element>
Is this a bug with polymer, or (infinitely more likely) user error?
Your code:
Polymer('#stream', {
this.accesstoken = document.querySelector('app-globals').accesstoken;
this.userid = document.querySelector('app-globals').userid;
this.streamparams = {
"access_token": this.accesstoken,
"user_id": this.userid
};
});
should at least look like this:
Polymer('#stream', {
accesstoken: document.querySelector('app-globals').accesstoken,
userid: document.querySelector('app-globals').userid,
streamparams: {
"access_token": this.accesstoken,
"user_id": this.userid
},
});
Use a code linter and you will find those errors (Syntax Errors) before you even run your code.
But nevertheless there are more errors in your code. Go ahead and read the awesome polymer docs.

Resources