2

I want to know how can I pass variables to vue component in laravel?

When we work with blade we can pass variables like:

$now = Carbon::now();
return view('xxxxxxxx', compact('now');

That way I can use $now in xxxxxxxx blade file. But what about vue components? we usually return data by json for components and with axios route we get that info no way to specify such data for exact component of us?

What if I want to use $now = Carbon::now(); in single.vue component?

How can I make that happen?

Update

Here is what I want to do with timing as carbon cannot be used (based on comments) I want to use moment.js

Logic

  1. Let users bid if project deadline hasn't arrived
  2. Don't let users bid if project deadline has arrived

template

<template v-if="`${project.deadline | timeAgo}`">
  pssed (will be replaced by button is just for test)
</template>
<template v-else>
  still have time (will be replaced by button is just for test)
</template>

script

var moment = require('moment');
export default {
        data(){
            return {
                project : '',
            }
        },
        mounted: function() {
            // I found this code by google not sure if is currect!
            Vue.filter('timeAgo', function(value){
                return moment(value) >= fromNow()
            });
        },
}

Based on my code above here is the results

one

Firouziam
  • 777
  • 1
  • 9
  • 31
mafortis
  • 6,750
  • 23
  • 130
  • 288
  • can't you use, i.e., moment.js or DateTime for that? anyway, there's php vars to JavaScript var package for Laravel by Jeffrey Way, I think you can use that and pass the variable to your component? Or just json encode and decode the php var into your component. – Wreigh Sep 10 '18 at 01:18
  • @Wreigh i am using moment.js currently in my component but is hard to do functions with it (at least for me!) for example i want to not let users do certain action after specific time reached (database based) with moment I have no idea how to do it while with carbon was piece of cake :\ – mafortis Sep 10 '18 at 01:21
  • ah, so, you want to use a Carbon object in Javascript together with its methods? I think that's not possible. because you'll have to serialize the whole PHP class for you to be able to use it, plus Carbon uses PHP's DateTime class I believe. What example functions do you want to use? – Wreigh Sep 10 '18 at 01:26
  • Would you mind to show your Vue component file? I'll be glad to help :D – krisanalfa Sep 10 '18 at 01:26
  • @krisanalfa updated my qustion bro, – mafortis Sep 10 '18 at 01:32
  • @Wreigh thanks for information bro, I also updated my question maybe you can help me better now? – mafortis Sep 10 '18 at 01:32
  • I think it's correct since `timeAgo` filter returns `return moment(value) >= fromNow()` so in your example, `9/19/2018 >= 9/10/2018` is true, thus showing `pssed`. Unless `fromNow()` does other things since I don't know where that function came from. – Wreigh Sep 10 '18 at 01:42
  • @Wreigh probably i'm confused at the moment, why it shows passed? my first elemet is `9/19/2018` it supposed to be not passed since today is `9/10/2018` so basically today is not `>` than `19 september` did i make mistake in my `v-if`? should i use some `!=` thing there? – mafortis Sep 10 '18 at 01:46
  • @Wreigh `fromNow` is moment function like `Carbon::now()` is not what i made. – mafortis Sep 10 '18 at 01:49
  • in your filter, you did `moment(value) >= fromNow()` in which you passed `project.deadline` so `value` will be equal to `09/19/2018` so, `09/19/2018 >= fromNow()` is true. – Wreigh Sep 10 '18 at 02:04
  • @Wreigh i don't know even i changed deadline in database to see if there is any change in all conditions it keep showing passed. – mafortis Sep 10 '18 at 02:15
  • See this for diffing momentjs dates. https://stackoverflow.com/a/27327083/6607392 – Wreigh Sep 10 '18 at 02:50

1 Answers1

0

Try this:

This is my routes, simply I just render a view with some pre-defined variables

Route::get('/', function () {
    return view('welcome', [
        'now' => Carbon::now(),
        'deadline' => Carbon::now()->addHours(2)
    ]);
});

And this is my view file. Here I have custom element named: example-component. And this is how I passed PHP variables to Vue component using props.

And pass your data to window like so:

<script>window.data = @json(compact('now', 'deadline'))</script>

And this is my Vue component file:

<template>
    <h1>
        <span v-if="isPassed">This job is passed</span>
        <span v-else>You have to finish this job</span>
        {{ parsedDeadline | timeFromX(parsedNow) }}
    </h1>
</template>

<script>
const moment = require('moment');

export default {
    props: {
        now: {
            type: String,
            default: () => window.data.now.date // since `now` is an object, you need to access the `date` property to get plain string date that moment can parse
        },
        deadline: {
            type: String,
            default: () => window.data.deadline.date // same as above
        }
    },
    computed: {
        parsedNow () {
            return moment(this.now)
        },
        parsedDeadline () {
            return moment(this.deadline)
        },
        isPassed () {
            return this.parsedNow.isAfter(this.parsedDeadline)
        }
    }
}
</script>

Here's the documentation about computed and filters. You may NEVER add a filter in a mounted function since it may leads to memory leak. Here's how I add my filter. In your app.js (assumed you're using default Laravel Vue preset)

/**
 * First we will load all of this project's JavaScript dependencies which
 * includes Vue and other libraries. It is a great starting point when
 * building robust, powerful web applications using Vue and Laravel.
 */

require('./bootstrap');

window.Vue = require('vue');

/**
 * Next, we will create a fresh Vue application instance and attach it to
 * the page. Then, you may begin adding components to this application
 * or customize the JavaScript scaffolding to fit your unique needs.
 */

Vue.component('example-component', require('./components/ExampleComponent.vue'));

Vue.filter('timeFromX', (a, b) => a.from(b)); // TADAAA...!!!

const app = new Vue({
    el: '#app'
});

UPDATE

If you want to try this, you may edit the routes/web.php and change the deadline value:

Route::get('/', function () {
    return view('welcome', [
        'now' => Carbon::now(),
        'deadline' => Carbon::now()->subHours(2), // Passed 2 hours ago
        // 'deadline' => Carbon::now()->addHours(2), // In 2 hours
    ]);
});

Checkout the Carbon docs here about addition and subtraction.

UPDATE II

If you got error in app.js from the code above, maybe your transpiler doesn't know about arrow-parens.

// Looks like arrow-parens not working, see code below
// Vue.filter('timeFromX', (a, b) => a.from(b)); // TADAAA...!!!

// Change it to this ???
Vue.filter('timeFromX', function (a, b) {
    return a.from(b);
});
tony19
  • 125,647
  • 18
  • 229
  • 307
krisanalfa
  • 6,268
  • 2
  • 29
  • 38
  • Hi, thanks for the answer. As I'm not using blade (at all) to refer to my components insead i'm using `router-view` i cannot use `` to add variables to my components, so I start to use `moment.js` but in all conditions it returns `v-if` and never `v-else` part. In comments was suggested to use `diff` https://stackoverflow.com/questions/27326937/how-to-do-a-greater-than-or-equal-to-with-moments-moment-js-in-javascript/27327083#27327083 but i don't know how to? regarding to my code. – mafortis Sep 10 '18 at 03:17
  • `PS` I added my filters to `app.js` as you suggested it return ` [Show/hide message details.] Error: Module build failed: SyntaxError: Unexpected token (1:2712)` (I added 2 filters there) – mafortis Sep 10 '18 at 03:17
  • Hi @mafortis, I've updated my answer. Just a small change, I pass the data to the window and let the component use it. About your `SyntaxError`, I think it's because of javascript transpiler issue. Can I see your `app.js` file? Just put it to your question and I'll help you out. – krisanalfa Sep 10 '18 at 03:33
  • I'm using `filters:{}` in my component now, and to avoid console errors I added `timeAgo: '',` to `data` now is working fine, is there any memory leak issue with that as well? – mafortis Sep 10 '18 at 03:40
  • No! Using `filters` in your component is good! Just avoid calling `Vue.filter` on mounted, because everytime your component mounted you'll find your `filter` would be overridden and it would tell your component to change (re-render). But I strongly suggest to put in on global filter (in this case in your `app.js` file) since you may re-use the logic for the other component ;). – krisanalfa Sep 10 '18 at 05:31