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
Related
Can anyone help me make translations working in laravel blades too?
I need to change/translate the contents of the title and description meta depending on the language being switched.
This is how the language changes in Vue:
<template>
<ul class='language-switcher'>
<li :class="{'active': language === 'de'}">
De
</li>
<li :class="{'active': language === 'en'}">
En
</li>
</ul>
</template>
<script>
import {loadLanguageAsync} from "laravel-vue-i18n";
export default {
name: "LanguageSwitcherComponent",
data() {
return {
language: 'en',
};
},
methods: {
switchLanguageTo(lang) {
// ...
loadLanguageAsync(lang);
// ...
},
},
}
</script>
In Vue, the translations work fine, but I need to translate title and description meta in index.balde.php as well.
<!DOCTYPE html>
<html lang="{{str_replace('_', '-', app()->getLocale())}}">
<head>
<title>{{ __("Site Title") }}</title>
<meta name="description" content="{{ __("Site Info") }}">
<meta charset="utf-8">
<meta name="csrf-token" content="{{ csrf_token() }}"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="{{mix('css/app.css')}}">
</head>
<body>
<div id="app">
<index-component/>
</div>
<script src="{{mix('js/app.js')}}"></script>
</body>
</html>
Also, this is how configured i18n in app.js:
import {i18nVue} from 'laravel-vue-i18n';
// ...
app.use(i18nVue, {
lang: 'en',
resolve: lang => import(`../../lang/${lang}.json`),
});
Thanks!
Save site language in cookies and in web.php set locale from cookies.
Route::get('/{any}', function (Request $request) {
// Set locale
App::setLocale($request->cookie('site_language') ?: 'en');
return view('index');
})->where('any', '.*');
Note: Maybe will need to add cookie name in app/Http/Middleware/EncryptCookies.php in $except list to get cookie from the $request successfully.
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\.-]*');
I have some common data getting from helper. Now I wanted to use that data in all over view. So, I am trying to declare that data in app.blade.php and trying to pass it's sections.
Here is my app.blade.php -
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- CSRF Token -->
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>ABC| #yield('title')</title>
<!-- Fonts -->
<link rel="dns-prefetch" href="//fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css?family=Nunito" rel="stylesheet">
<link href="{{ asset('/assets/plugins/bootstrap/css/bootstrap.min.css') }}" rel="stylesheet">
<link href="{{ asset('/assets/abc/css/style.css') }}" rel="stylesheet">
<?php
//get theme
$theme = AppHelper::instance()->getTheme();
//get theme folder
$themeFolder = $theme[0]->websiteAdmin;
//set include files section path
$includePath = 'frontend.'.$theme[0]->themeName.'.sections.';
?>
</head>
#yield('content')
</html>
Here I want to pass variables $theme, $themefolder, $includePath to #yield('content').
I tried below code -
#yield('content', array('theme'=> $theme, 'themeFolder'=> $themeFolder, 'includePath'=> $includePath))
But getting error that those variables are undefined.
Undefined variable: theme
Can you please help me how to pass data from #extend to #yield?
Thank you in advance.
You should use View composers to accomplish this. They allow you to pass the same data across multiple views by only calling it in one place.
In your providers/AppServiceProvider.php you can add the following to your boot method:
use Illuminate\Support\Facades\View; //import view facade
public function boot()
{
View::composer(['view-name', 'another-view-name'], function($view){
$theme = AppHelper::instance()->getTheme();
$themeFolder = $theme[0]->websiteAdmin;
$includePath = 'frontend.'.$theme[0]->themeName.'.sections.';
$view->with(compact('themeFolder', 'includePath', 'theme'));
});
}
View::composers first argument takes an array of views, put all the views you want to pass the data to here ['view-name', 'another-view-name'], it can also take a single string.
The data will now be available to your specified views through $themeFolder $includePath and $theme variables
If you want this data to pass to ALL views, you can do '*' as the first argument.
NOTE, this will pass the data to EVERY view you create, only do '*' if you want every view to contain the data! Otherwise, specifiy the views individually.
If you want all the views within a certain folder to get passed the data you can do 'folder-name.*'.
Alternatively, the only other way to pass data to your #yield is to return the view app.blade.php with the variables in your controller.
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
im using a laravel 5.4 and i have a problem with urls, when i send value with urls like http://localhost:8000/Music/{id} , laravel does not load styles but if use url without value to get that view it loads styles properly, it also does not load styles if an slash get added to end of url like http://localhost:8000/videos/ but without that slash http://localhost:8000/videos works without problem ..sorry i cant speak english good.
here is my code :
Route::get('Music/{id}','homeController#Music');
public function Music(music $item)
{
return view('music',['item'=>$item]);
}
this works by route model binding properly and does what i want but when it returns music blade file it does not load styles that i linked but if use this instead :
Route::get('Music','homeController#Music');
a
public function Music()
{
$item = music::find(1); //for example
return view('music',['item'=>$item]);
}
that works perfect.
i checked this many ways its because of {vlaues} in urls
it also does not loads styles or js files if an slash get added to end of urls
what is the problem?
Use the asset() function...
<html>
<head>
<link href="{{ asset('css/test.css') }}" rel="stylesheet">
</head>
<body>
<div class="square"></div>
<!-- Same for Javascript... -->
<script src="{{ asset('js/app.js') }}"></script>
</body>
</html>
i tested it on this too
<html>
<head>
<link rel="stylesheet" href="css/test.css" type="text/css">
</head>
<body>
<div class="square"></div>
</body>
</html>