I'm using "vue-i18n": "^7.6.0" on laravel 5.6, vuejs for translating the website into 16 languages.
I have mentioned all the languages in config/app.php and i have created a folder lang in resources/assets/js/lang where i have all the language files (example, en.json, es.json and so on). I have created a dropdown and everything works fine as expected.
Now i need to create Articles table. What im looking for is creating the article in multiple languages and storing in database like
articles (table)
article_languages(id, article_id lang content) something like this
And use these translations along with the main translations i have created with json files. How to achieve this?
ArticleController
<?php
namespace App\Http\Controllers\Articles;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Models\ArticleCategory;
use App\Models\Article;
use App\Models\ArticleTranslation;
class ArticleController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index($language)
{
$articles = Article::withTranslations($language)->get();
return $articles;
}
I've installed this package and followed their instructions
ArtcileComponent
<template>
<div>
<ul>
<li>{ article.title }</li>
<li>{ article.subtitle }</li>
<li>{ article.content }</li>
</ul>
</div>
<template>
<script>
export default {
data: function () {
return {
articles: []
}
},
mounted() {
var app = this;
axios.get('/api/articles/' + self.$i18n.locale + '/')
.then(function (response) {
self.articleText = response.data.article;
})
.catch(function (error) {
console.log(error);
});
}
}
</script>
In Vue you send a get request over to Laravel via an API. The self.$i18n.locale variable holds the library locale.
let self = this;
axios.get('/articles/' + self.$i18n.locale + '/' + article.id)
.then(function (response) {
self.articleText = response.data.article
})
.catch(function (error) {
// Do something with the error
console.log(error)
});
Your Laravel route would look something like this:
use App\AppArticle;
Route::get('articles/{language}/{id}', function ($language, $id) {
return App\ArticleLanguage::where('article_id', $id)->where('lang', $language)->firstOrFail();
});
Related
I am new to laravel and I am sorry that my English is so bad.
I create app that has many-to-many relations with laravel + vue.
The relationship between models is recipe and category.
I am trying to store a recipe related to the category.
but when submitting recipe data with form tag, error occure.
The error is below.
local.ERROR: Class "App\Http\Controllers\Category" does not exist {"exception":"[object] (ReflectionException(code: -1): Class "App\Http\Controllers\Category" does not exist at /home/sakamotosora/Desktop/recipehouse-laravue/vendor/laravel/framework/src/Illuminate/Routing/RouteDependencyResolverTrait.php:81)
[stacktrace]
The code I wrote looks like this.
// RecipeController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Recipe;
use Illuminate\Support\Facades\Log;
class RecipeController extends Controller
{
public function store(Category $category, Reqeust $request)
{
logger()->error();
$recipe = new Recipe();
$recipe->title = $request->title;
$recipe->save();
return redirect()
->route('category.show', $category);
// return back();
}
}
// CategoryShowCOmponent.vue
<script setup>
const props = defineProps({
categoryId: String,
})
const newRecipe = ref('')
let categoryId = parseInt(route.params.categoryId)
const addRecipe = () => {
recipes.value.push(newRecipe.value)
submitNewRecipe()
newRecipe.value = ''
}
const submitNewRecipe = () => {
axios.post('/api/categories/' + categoryId + '/recipes/store', {
title: newRecipe.value
})
}
</script>
<template>
<form method="post" v-on:submit.prevent="addRecipe">
<input type="text" v-model="newRecipe">
</form>
</template>
Since the amount of code is large, irrelevant code is omitted.
// api.php
Route::post('/categories/{category}/recipes/store', [RecipeController::class, 'store']);
I checked for typo for example, Recipecontroller (c is lower case)
thankyou for your help!
You need to add use App\Models\Category; on top of controller.
Update, Next there is a type on Request as well, you need to update to:
public function store(Request $request, Category $category)
you are using Reqeust instead.
Also, I am not sure, if there will $category on store case, because the model might only be supplied while updating.
Sometimes I need to pass data from my controller to the view and sometimes I dont!
But when theres no data passed I get this error:
Undefined variable: tutorial (View:
/var/www/html/resources/views/home.blade.php)
No data example:
public function index()
{
return view('home');
}
Containg data example
public function tutorial()
{
return view('home', ['tutorial' => 'Welcome to myproject, lets get started!!!']);
}
Blade:
beforeMount()
{
let tutorial = {{ var_export($tutorial) }} // ERROR!!
if (tutorial) {
return
}
this.reloadData()
}
I think I can do this way in my index function:
public function index()
{
return view('home', ['tutorial' => []);
}
But its just gross!! Theres anyway to check if data passed from laravel exists in my vue??
Because you cannot just put the Laravel variable in js.
Options to solving the problem included:
Performing an api request for the data using the application
component once it had been mounted.
Attaching the data into the
Javascript context using the blade template.
You can do some thing like this:
<Home tutorial="{{ $tutorial }}"> <!-- make tutorial become to props -->
</Home>
And in your view component:
Vue.component('Home', {
props: [
{
name: 'tutorial', // add this props
default: '',
}
],
beforeMount()
{
if (this.tutorial) { // use like this.tutorial
return
}
this.reloadData()
}
});
I am in the process of integrating Laravel Permission API with Vue.JS frontend. I am using https://github.com/spatie/laravel-permission library for Laravel Permission. I am not understanding how can I check permission in the Vue JS front End (In Laravel blade I am using #Can to check the permission).
I will do a ajax call to check for permissions instead , something like this, but of cours eyou need to modify it to cater your needs.
Routes:
Route::get('/permission/{permissionName}', 'PermissionController#check');
Controller:
function check($permissionName) {
if (! Auth::user()->hasPermissionTo($permissionName)) {
abort(403);
}
return response('', 204);
}
Vue: (if you wanna do this synchronously), this is a simple example (Vue global mixin), you can turn this into Vue directive or component.
Vue.mixin("can", (permissionName) => {
let hasAccess;
axios.get(`/permission/${permissionName}`)
.then(()=> {
hasAccess = true;
}
.catch(()=> {
hasAccess = false;
};
return hasAccess;
});
And then everytime you wanna check permission, you can just do
<el-input v-if="can('write-stuff')"> </el-input>
I'm literally working on this exact same thing. I'm thinking of adding a custom Vue directive that would check against the Laravel.permissions array.
It might even be as simple as
Vue.directive('can', function (el, binding) {
return Laravel.permissions.indexOf(binding) !== -1;
})
I haven't tested this code. Just brainstorming here.
<button v-can="editStuff">You can edit this thing</button>
I can hold permissions this way:
window.Laravel = <?php echo json_encode([
'csrfToken' => csrf_token(),
'userId' => Auth::user()->id,
'permissions' => Auth::user()->permissions()->pluck('name')->toArray()
]); ?>
Just stumbled upon this problem and I would like to share what I found and implemented.
Add an accessor on the User model the spatie/laravel-permission is using
public function getAllPermissionsAttribute() {
$permissions = [];
foreach (Permission::all() as $permission) {
if (Auth::user()->can($permission->name)) {
$permissions[] = $permission->name;
}
}
return $permissions;
}
On your global page or layout page pass the permission from the accessor to the javascript.
<script type="text/javascript">
#auth
window.Permissions = {!! json_encode(Auth::user()->allPermissions, true) !!};
#else
window.Permissions = [];
#endauth
</script>
Create a global directive on resources/js/app.js
Vue.directive('can', function (el, binding, vnode) {
if(Permissions.indexOf(binding.value) !== -1){
return vnode.elm.hidden = false;
}else{
return vnode.elm.hidden = true;
}
})
Here you are checking if the permission you supplied on the directive is on the permission array from laravel.
If found then it will hide the element else show, this function is like a v-if.
Use it like this on your component - "add_items" is your permission
<button type="button" v-can="'add_items'"></button>
This solution is from this but instead of a mixin, I use a directive.
Got the idea of directive from #Ismoil Shifoev comment above.
You can use this format in Vuejs for Laravel Permission:
<div v-if="can('edit post')">
<!-- Edit post form -->
</div>
<div v-if="is('super-admin')">
<!-- Show admin tools -->
</div>
add function to User Model to get all user permissions&roles like this:
class User extends Authenticatable
{
// ...
public function jsPermissions()
{
return json_encode([
'roles' => $this->getRoleNames(),
'permissions' => $this->getAllPermissions()->pluck('name'),
]);
}
}
pass this data to JavaScript in HTML header:
<script type="text/javascript">
window.Laravel = {
csrfToken: "{{ csrf_token() }}",
jsPermissions: {!! auth()->check()?auth()->user()->jsPermissions():null !!}
}
</script>
in app.js file add global Vuejs can function to check user permissions and is function to check user roles:
Vue.prototype.can = function(value){
return window.Laravel.jsPermissions.permissions.includes(value);
}
Vue.prototype.is = function(value){
return window.Laravel.jsPermissions.roles.includes(value);
}
https://github.com/ahmedsaoud31/laravel-permission-to-vuejs
I would go with Ralph solution. But I find myself better using. This function to fetch the Permissions.
public function getAllPermissionsAttribute() {
return Auth::user()->getAllPermissions()->pluck('name');
}
Just a bit cleaner, and since I tend to use Roles instead of particular permissions for each User, this solution should work as well.
My ajax (in vue component) like this :
<template>
...
<a class="text-right" #click="detail">
Detail
</a>
...
</template>
<script>
export default{
...
methods:{
...
detail() {
this.$http.post(window.BaseUrl + '/shop/',{data: JSON.stringify(this.data)}).then(function (response) {
...
}).catch(function(error){
...
});
}
}
}
</script>
If user click a link, it will call detail method
In detail method used to send data via ajax
It will routes in laravel
The route like this :
Route::group(['prefix' => 'shop','as'=>'shop.'], function () {
Route::post('/', 'ShopController#index');
...
});
Then the route will call shop controller
The controller like this :
public function index(Request $request)
{
$param = $request->only('data');
$list = $this->shop_service->getList($param['cart_cache']);
return view('shop.index',compact('list'));
}
If the code executed, I want it will redirect to view blade laravel (return view('shop.index',compact('list'));)
How can I do it?
You can redirect to route in Ajax success which will call your desired funtion in controller like this:
Ajax
success:function(){
window.location.href(base_url+"/get/data");
});
For this to work, you should have following route and controller function
Route
Route::get('/get/data','YourController#getData');
Controller
public function getData(){
$list = // here write code to get desired data.
return view('shop.index',compact('list'));
}
Hope you understand.
I am upgrading my guitar lessons site from 5.2 to 5.3. My previous developer has a full time job so now I am the site owner and developer... I am a better guitarist than developer...
My site has a backend for adding guitar lesson content. The routes.php file, among other things, had these lines:
function RegisterResourceRoute($route, $name) {
Route::get($route, 'Api\\'.$name.'Controller#getAll');
Route::get($route.'/{id}', 'Api\\'.$name.'Controller#get');
Route::post($route, 'Api\\'.$name.'Controller#post');
Route::put($route.'/{id}', 'Api\\'.$name.'Controller#put');
Route::delete($route.'/{id}', 'Api\\'.$name.'Controller#delete');
}
// Api
Route::group(['middleware' => ['api', 'auth', 'admin']], function () {
Route::group(array('prefix' => 'api'), function() {
RegisterResourceRoute('file', 'File');
RegisterResourceRoute('photo', 'Photo');
RegisterResourceRoute('category', 'Category');
RegisterResourceRoute('tag', 'Tag');
RegisterResourceRoute('lesson', 'Lesson');
RegisterResourceRoute('exercise', 'Exercise');
RegisterResourceRoute('user', 'User');
});
Route::post('/api/email', 'Api\\EmailController#send');
});
Then I see in the angular related js used in the view, this for the Exercise resource:
// Exercise
.when('/exercise', {
templateUrl: 'views/dashboard/exercise/view-all.html',
controller: 'ExerciseViewAllController'
})
.when('/exercise/create/:lessonId?', {
templateUrl: 'views/dashboard/exercise/create.html',
controller: 'ExerciseCreateController'
})
.when('/exercise/view/:id', {
templateUrl: 'views/dashboard/exercise/view.html',
controller: 'ExerciseViewController'
})
.when('/exercise/edit/:id', {
templateUrl: 'views/dashboard/exercise/edit.html',
controller: 'ExerciseEditController'
})
.when('/exercise/edit/:id/details', {
templateUrl: 'views/dashboard/exercise/edit-details.html',
controller: 'ExerciseDetailsController'
})
.when('/exercise/edit/:id/photos', {
templateUrl: 'views/dashboard/exercise/edit-photos.html',
controller: 'ExercisePhotosController'
})
.when('/exercise/delete/:id', {
templateUrl: 'views/dashboard/exercise/delete.html',
controller: 'ExerciseDeleteController'
})
The ViewAllController, for instance, looks like this:
angular.module('dashboard')
.controller('ExerciseViewAllController', ['$scope', '$http', function ($scope, $http) {
$scope.exercises = [];
$scope.refresh = function () {
$scope.exercises = [];
load();
};
var load = function () {
$scope.busy = true;
$http.get('/api/exercise').then(function (response) {
$scope.busy = false;
$scope.exercises = response.data;
}, function (response) {
$scope.busy = false;
});
};
load();
}]);
I am trying to figure out how 5.3 handles such routing. In my backend dashboard, when I try and view the list of exercises, for instance, I was getting a 404 error for api/exercise.
So I created web.php with this under admin routes:
Route::resource('api/exercise', 'Api\ExerciseController');
And in api.php
Route::group(['prefix' => 'api'], function () { Route::resource('exercise', 'Api\ExerciseController'); });
It now works, but I had to change what was previously a getAll() function in the Exercise controller to index(), otherwise there was a error since laravel was looking for the default index method.
I would rather get it working using default route names, and also I have no idea if what I added to web.php and api.php is really the correct way. I see things seem to work but I am worried I am not seeing the whole picture...
Can someone explain what I would do to get these routes working in the true laravel 5.3 way?
thanks!
Not remember exactly but I upgraded from 5.2 to 5.3 by this link https://laravel.com/docs/5.3/upgrade
Do not get overwhelmed by the content. just search for bits that you are getting errors from. for example routes section.
Hope that helps