Getting env data in vue component - laravel

How can I have .env data such as APP_NAME in my components?
Let say I want to show to users Welcome to {{APP_NAME}}
UPDATE
Base on this document I've made changes in my env file and like:
MIX_APP_NAME=Laravel
and added this to my component script:
data() {
return {
app_name: process.env.MIX_APP_NAME,
}
},
Now I can have my app name in my component but the issue is I want to use it in bootstrap tooltip and there gives me this error:
- title=".... by {{app_name}}": Interpolation inside attributes has been removed. Use v-bind or the colon shorthand instead. For example, instead of <div id="{{ val }}">, use <div :id="val">.
My code:
<span data-toggle="tooltip" data-placement="top" title="... {{app_name}}"></span>
Any idea?

First add to env file:
MIX_APP_NAME=Laravel
and add this to your component script:
data() {
return {
app_name: process.env.MIX_APP_NAME,
}
},
Now you can use it like this:
<div :title="`text ${app_name}`"></div>
Or:
{{ app_name }}
Source

thats worked for me without adding any require in webpack.mix
... just add a new variable in env file with this prefix : MIX_
BUT need to restart with php artisan serve and also restart with npm run watch ....

you can directly use it as process.env.APP_NAME
mounted(){
this.appName=process.env.APP_NAME
}

Related

Accessing Laravel's .env variables inside Inertia.js Vue files

I am starting with the Inertia Laravel example https://github.com/drehimself/inertia-example
which is nothing but Laravel with Vue in one monolithic codebase, using Inertia.js:
https://github.com/inertiajs/inertia-laravel
https://github.com/inertiajs/inertia-vue
I am trying to access Laravel's .env variables inside my .vue component files
.env file:
APP_NAME=ABC
In app\Providers\AppServiceProvider.php:
public function register()
{
Inertia::share('appName', env('APP_NAME'));
}
In resources\js\Home.vue component:
<template>
<div>
<span class="tw-text-left">{{ appName }}</span>
</div>
</template>
<script>
export default {
props: [
"appName",
]
}
</script>
In my vue console, appName shows up blank. It should show "ABC" but doesn't.
What's going on here, and how I can access all my env variables, ideally without passing everything through the controller, which doesn't seem very efficient?
I finally got it working. Here's how, for those interested:
In AppServiceProvider:
Inertia::share(function () {
return [
'app' => [
'name' => config('app.name'),
],
];
});
In your vue file:
<template>
<div>
App name: {{ $page.app.name }}
</div>
</template>
The 2nd part is what I was missing..I was trying to accept the app.name prop, and was missing $page.
Hope this helps somebody!
I know this is kind of old, but I ran into this same issue and the methods above and around the net did not work for me. Something might have changed with Inertia? Anyway, I did get it working though.
Just like above add the following to the register method within your AppServiceProvider:
Inertia::share('appName', config('app.name'));
// I'm using config, but your could use env
Then in your Vue component access the $inertia variable like so:
{{ $inertia.page.props.appName }}
From the documentation on the author's website, you need to instruct vue to inject the page into your component, and then you can accessed the shared variables.
For example:
<template>
<div>
<span class="tw-text-left">{{ page.props.appName }}</span>
</div>
</template>
<script>
export default {
inject: ['page'],
// ...
}
</script>
if you want to share multiple variables with view use the following:
Inertia::share('app', [
'name' => config('app.name'),
'url' => config('app.url'),
]);

Passing and binding img src from props in Vue.js

I am trying to display an image with the img tag by using a path from props for the src attribute.
I've tried changing the path with #, using the whole path with src, adding ../assets/ in the component and only passing the file name (orange.png) as props.
I always get the default broken image displayed.
When inspecting in the browser, the path seems fine.
When I display the image directly, I can see that the path is resolved to some different path <img data-v-1212d7a4="" src="/img/orange.7b71a54c.png">.
Edit:
Additionally I tried this post Can't dynamically pass relative src path for imgs in Vue.js + webpack ,
where using <img :src="require(picture_src)" /> is given as an answer.
This leads to an error: Error in render: "Error: Cannot find module '../assets/orange.png'"
(Edit2:
This answer in the end worked for me in the end as described in my answer post.)
The same error occurs with the similar webpack method using let images = require.context('../assets/', false, /\.png$/) in my script part, as the answer on this post Can't dynamically pass relative src path for imgs in Vue.js + webpack .
I am new to Vue.js, so I don't exactly know what is happening or how to search for this or it might not have anything to do with what I'm originally trying.
I am able to display my image when I pass the path directly, like this
<img src="../assets/orange.png"/>
Now I'd actually like to pass it to my component in the props and then, inside the component, display it reading the path from props.
Component
<template>
<div>
<img :src=picture_src />
<div class="pic_sub">{{pic_desc}}</div>
</div>
</template>
<script>
export default {
name: 'PictureCard',
props: {
picture_src: String,
pic_desc: String
}
}
</script>
Using the component:
<template>
<div>
<PictureCard pic_desc='some description text' picture_src='../assets/orange.png' />
</div>
</template>
<script>
import PictureCard from './components/PictureCard.vue'
export default {
name: 'app',
components: {
PictureCard
}
}
</script>
If it is possible, I'd love to display my from a path that is passed through the component's props.
Otherwise I'd love to know some other solutions, work-arounds or knowledge on best practices in this case.
This worked for me
<img :src="require(`#/assets/img/${filename}`)">
where filename is passed in as a String prop e.g. "myImage.png".
Make sure you use the path specific to your project.
Source: https://github.com/vuejs-templates/webpack/issues/450
Note: # is a webpack alias for /src that is set by default in Vue projects
After some research, I understand that my problem has to do with webpack and resolving filepaths. I used a modified version from this answer:
Vue.js dynamic images not working
and this answer:
Can't dynamically pass relative src path for imgs in Vue.js + webpack
Since the link in the second answer was dead, here's an active link to require.context documentation:
https://webpack.js.org/guides/dependency-management/#requirecontext
My mistake when trying the second link's answer was that I returned only orange.png as the path, while I needed to add ./ at the beginning.
My working picture component now looks like this.
<template>
<div>
<img :src="resolve_img_url(picture_src)" />
<div class="pic_sub">{{pic_desc}}</div>
</div>
</template>
<script>
export default {
name: 'PictureCard',
props: {
picture_src: String,
pic_desc: String
},
methods: {
resolve_img_url: function (path) {
let images = require.context('../assets/', false, /\.png$|\.jpg$/)
return images("./"+path)
}
}
}
</script>
I edited the regular expression to match .png and .jpg file endings. Therefore passing the prop looks like this now
<PictureCard picture_src='orange.png' pic_desc='some picture description'/>
This works for me:
This is how i use my Componenent.
<image-element
:imageSource="require('#/assets/images/logo.svg')">
</image-element>
My Image Component:
<template>
<div>
...
<img v-bind:src=imageSource />
...
</div>
</template>
<script lang="ts">
import Vue from 'vue'
import { Component, Prop } from 'nuxt-property-decorator'
#Component({
components: {
.....
}
})
export default class extends Vue {
...
#Prop({ default: '' }) imageSource!: String
...
}
</script>
Newer solution:
The 'require()'-method does not work when using Vite.
I got this error: ReferenceError: require is not defined.
This is how I solved it without 'require()' and with composition API:
From parent component:
<ChildComponent icon-filename="icon.svg" />
ChildComponent:
<template>
<div>
<img :src="getImageUrl()">
</div>
</template>
<script setup lang="ts">
import {defineProps} from "vue";
const props = defineProps({
iconFilename: String
})
function getImageUrl() {
// This path must be correct for your file
return new URL(`../assets/icons/${props.iconFilename}`, import.meta.url)
}
</script>
this is my favorite super simple way to do it. It can easily be reused in any file in any folder in my project. Just pass the actual path as a string from the perspective of the parent:
//some file
<ParentA>
<ImageComponent
myImagePath="../../../../../myCat.png"
/>
</ParentA>
//some other file in a different folder in my project
<ParentB>
<ImageComponent
myImagePath="../../myCat.png"
/>
</ParentB>
//child component file
<template functional>
<div>
<img :src="props.myImagePath">
</div>
</template
Thats all not working for me :D
The template File is wrong!
you need to add ":" before you set your prop.
thats how i should use the PictureCard
<PictureCard :picture_src="require('orange.png')"
pic_desc='some picture description'/>
and thats how my PictureCard should look like:
<template>
<div>
<img v-bind:src="picture_src" />
</div>
</template>
export default class PictureCard extends Vue {
#Prop({ default: require("#/assets/orange.svg") }) img!: string
}
so in case no prop is setted, so i added a default prop too.
and yes i only used the image.

What is the best way to use v-model without using it in the main app.js file?

I was wondering i have this code inside my blade file:
<input type="text" class="form-control" :model="productname" id="name" name="name" aria-describedby="emailHelp" placeholder="Title" value="{{ old('name') }}" required>
and i want to create an 2 way data binding, so when user submitted 3 or more character to get an green background of this input field, but when they are less to get a red background.
I tried to do this with vue-component, but it seems for whatever reason the vue-component does not have access to the main #app id which is assign to the main app blade template in order all vue code to have access to the html code and change it. I have created an vue-component called Upload inside ressources/assests/js/components/Upload.js, but when i write this code:
<template>
</template>
<script>
export default {
data() {
return {
productname: '',
};
},
mounted() {
console.log('Upload component', this.message);
}
}
</script>
and added of course to app.js like that Vue.component('upload-component', require('./components/Upload.vue'));
and run - npm run dev to compile the code i am getting this error:
[Vue warn]: Property or method "productname" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://v2.vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.
Whatever when i write this code inside the main app.js file (resources/assests/js/app.js):
const app = new Vue({
el: '#app',
data() {
return {
productname: '',
};
},
});
everything is working fine and i dont get any errors, but i dont want that, as imagine for my website/app i have to have for example 100 v-models and i dont want to put them all inside the main app.js file. Is there other way to do this?
Can i still somehow make it work inside the vue component, so the component can see the v-model and not giving me this error?
If not, can i make it work and use vue inside the blade file something like that?
new Vue({
el: '#form',
data: {
productname: ''
}
});
but this code its not working. Thanks!
It's a bit tricky to make out what you are doing exactly, but your error is related to having no data property 'message', you have only a property called 'productname'.
If you want your component to communicate up to its parents or siblings you should read into emitting events in vue using
this.$emit

Pass data from blade to vue component

I'm trying to learn vue and with that I want to integrate it with laravel too..
I simply want to send the user id from blade to vue component so I can perform a put request there.
Let's say I have this in blade:
<example></example>
How can I send Auth::user()->id into this component and use it.
I kept searching for this but couldn't find an answer that will make this clear.
Thanks!
To pass down data to your components you can use props. Find more info about props over here. This is also a good source for defining those props.
You can do something like:
<example :userId="{{ Auth::user()->id }}"></example>
OR
<example v-bind:userId="{{ Auth::user()->id }}"></example>
And then in your Example.vue file you have to define your prop. Then you can access it by this.userId.
Like :
<script>
export default {
props: ['userId'],
mounted () {
// Do something useful with the data in the template
console.dir(this.userId)
}
}
</script>
If you are serving files through Laravel
Then here is the trick that you can apply.
In Your app.blade.php
#if(auth()->check())
<script>
window.User = {!! auth()->user() !!}
</script>
#endif
Now you can access User Object which available globally
Hope this helps.
Calling component,
<example :user-id="{{ Auth::user()->id }}"></example>
In component,
<script>
export default {
props: ['userId'],
mounted () {
console.log(userId)
}
}
</script>
Note - When adding value to prop userId you need to use user-id instead of using camel case.
https://laravel.com/docs/8.x/blade#blade-and-javascript-frameworks
Rendering JSON
Sometimes you may pass an array to your view with the intention of rendering it as JSON in order to initialize a JavaScript variable. For example:
<script>
var app = <?php echo json_encode($array); ?>;
</script>
However, instead of manually calling json_encode, you may use the #json Blade directive. The #json directive accepts the same arguments as PHP's json_encode function. By default, the #json directive calls the json_encode function with the JSON_HEX_TAG, JSON_HEX_APOS, JSON_HEX_AMP, and JSON_HEX_QUOT flags:
<script>
var app = #json($array);
var app = #json($array, JSON_PRETTY_PRINT);
</script>
Just to add for those who still get error.
For me this <askquestionmodal :product="{{ $item->title }}"></askquestionmodal> still gives error in console and instead showing html page I saw white screen.
[Vue warn]: Error compiling template:
invalid expression: Unexpected identifier in
Coupling to connect 2 rods М14 CF-10
Raw expression: :product="Coupling to connect 2 rods М14 CF-10"
Though in error I can see that $item->title is replaced with its value.
So then I tried to do like that <askquestionmodal :product="'{{ $item->title }}'"></askquestionmodal>
And I have fully working code.
/components/askquestionmodal.vue
<template>
<div class="modal-body">
<p>{{ product }}</p>
</div>
</template>
<script>
export default {
name: "AskQuestionModal",
props: ['product'],
mounted() {
console.log('AskQuestionModal component mounted.')
}
}
</script>

Vue 2.2.2 doesn't display the data to the View

Current Version : Laravel 5.2 using only Browserify not Webpack
I've already set up everything such as like this:
In my resources/js/app.js
window.Vue = require('vue');
new Vue({ el : '.row',
data : { name: '' }
});
in my view :
<div class="row">
<input type ="text">
<h1> #{{ name }} </h1>
</div>
But when i try to refresh it. The DOM just renders for about 2ms or let's say split second then it's gone and there's an error that says :
[Vue warn]: You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build.
(found in )
You're using the runtime-only build but you likely need the standalone build, to do that simply add the following to your your package.json to alias the standalone build (which includes the template compiler) :
"browser": {
"vue": "vue/dist/vue.common.js"
}

Resources