object is undefind when passing from blade to vue component using props - javascript

I'm trying to pass an array from async method in the controller to a vue component using props through the blade, but I'm getting undefined when I try to console.log it in the vue component, this is my code:
Controller:
public function index(){
$pool = Pool::create();
$pool[] = async(function () {
return Rfm::all();
})->then(function ($output) {
$this->results=$output;
});
await($pool);
return view ("/dashboard", ["data" => $this->results]);
Blade:
<div id="total_customers">
<total-customers :data="{{$data}}"></total-customers>
</div>
Vue component:
export default {
props: ['data'],
data() {
return {
};
},
mounted() {
console.log(this.data);
}
};
I've searched and read somewhere that using async in the controller would be the problem as the object is still empty when it render to vue component, but I'm not sure about that, am i doing it wrong?

Binding props that way might work with strings and integers but doesn't work with array/object data: https://laravel.com/docs/9.x/blade#blade-and-javascript-frameworks
The following should work:
<total-customers :data="{{ Js::from($data) }}"></total-customers>
Addition:
Might want to look into https://inertiajs.com/ if you bind data to vue components in blade a lot, its a nicer way to render vue components with props

Related

Render a child component only after async method is completed in parent's mounted

I have a parent component which renders a child component. I am making an async call (an axios 'get' request from Vuex actions) from inside the mounted of the parent component, which fetches the data required for the child component.
I want to prevent the rendering of the child component til that async call is completed. Can someone suggest some elegant approach?
v-if
<child v-if="mydata" />
mydata can be a data property initialized to null:
data() {
return {
mydata: null
}
}
When that's populated in created/mounted, the child component will show.
async created() {
const response = await axios // ...
this.mydata = response.data;
}
EDIT: Based on your comments below. For Vuex, do this instead:
Continue using the v-if
Use a computed instead of a data property:
computed: {
mydata() {
return this.$store.state.mydata;
}
}
alternate syntax using mapState
import { mapState } from 'vuex';
computed: {
...mapState(['mydata'])
}

how to reactively render external array in vuejs

I made a small library to track the loading of all my api calls.
It basically is an array which contains objects describing one loading process. I import this library into a Single File Component to make calls to it. I then pass the array from the library to a child component and want to render all my objects in the array (the loading statuses). I see the data updating in Vue Devtools on the child component, however it is not updated in the page.
What i tried:
passing the vue instance from the parent component and use $set to update the array
using array.splice to update the array
creating a new object with Object.assign, update the new object and then update the array (splice/$set)
passing a key and updating this key when updating thew object
calling methods in the library in the console
sample updating function:
function _finish(name, descFinished) {
const i = _loaders.findIndex(l => l.name == name);
if(i < 0) throw new NameNotFoundException(name);
let loader = Object.assign({}, _loaders[i]);
if(descFinished != undefined) loader.descFinished = descFinished;
loader.loading = false;
loader.error = false;
loader.endTime = new Date();
vm.$set(_loaders, i, loader);
return _loaders[i];
}
I pass to the child component like this
<loading-status v-if="loadstatus" :statuses="loadstatus.getAllLoaders()"></loading-status>
child component looks this this
<template>
<div v-if="statuses">
<div v-for="status in statuses" :key="status.name">
<div>
{{ status.loading == true ? 'true' : 'false' }}
</div>
</div>
</div>
</template>
<script>
export default {
name: 'loading-status',
props: {
statuses: {
type: Array,
required: true
}
}
}
image of the array not being reactive on the page
some more information that may be useful:
the library structure:
function loadmanager(vueinstance) {
//library internals here
// for example my array i want to render:
let _loaders = [];
var publicInterface() {
//public accesable functions here
//i call this to pass the array to my child component
getAllLoaders() {
return _loaders;
}
}
return publicInterface;
}
exports.makeLoadManager = loadmanager;
i import the library in the vue SFC and call it in the mounted hook
import loadhelper from "../../helpers/Loadstatus.js";
...
data() {
return {
loadstatus: null
}
}
...
mounted() {
this.loadstatus = loadhelper.makeLoadManager(this);
}
My question boils down to: How do I reactively render or correctly update an array from a js library in vue.
I would be happy to provide more information if that helps answering my question.
If your library is creating (and managing) an array of "loaders", simplest thing you can do is define empty reactive array in your Vue component's data and in mounted hook assign a reference to your's library array into it. Like this:
import LoadingStatus from "./components/LoadingStatus";
import loadhelper from "./helpers/LoadManager.js";
export default {
name: "App",
components: {
LoadingStatus
},
data() {
return {
statuses: []
};
}
mounted() {
this.statuses = loadhelper.getAllLoaders();
}
};
Vue takes the array provided by your library and makes it reactive. You can use template like this:
<LoadingStatus :statuses="statuses"/>
See the demo
As long as both Vue and your "load manager" are working with the same array (reference), its all good. I'v added setTimeout callback into LoadManager to demonstrate that changes "from the outside of Vue" to the array will make Vue component re-render....

How to loop over components object in the template?

Usually we define in a Nuxt.js component something like this:
<script>
export default {
components: {
// components
}
data() {
return {
// key/value data
}
},
methods: {
// method definitions
}
}
</script>
Is there a way to read the components object as we read data() and methods ?
This is because I have several components and I want to loop on them to refactor parts of my code.
You can get Component data by using $options.
Try this.
created() {
console.log(this.$options.components)
}
it returns an object, keys are the component names, values are the contructors.
codepen - https://codesandbox.io/s/yk9km5m0wv

Accessing data in vue component

Im trying to access some data I have binded to a component with no luck. How should I do that?
My component:
export default {
name: 'component-vallingby',
data() {
return {
}
},
created() {},
methods: {}
}
Here's where im rendering it. Offer is an object:
<component-vallingby v-bind="{ offer: offer }"></component-vallingby>
Pass the prop to the component like :order="order". Inside the component vm, list this in props array as a String.
export default {
name: 'component-vallingby',
props: ['offer']
}
Then instantiate your component passing order like this:
<component-vallingby :offer="offer"></component-vallingby>
You need props inside of your export default {} mentioned.
props: ['offer']
You should bind it as
<component-vallingby :offer="offer"></component-vallingby>

Equivalent of a React container and presentational component in Vue.js

I would like to separate the business logic and the template of a component.
In React I would use the Container/Presentation pattern.
const Container = (props) => <Presentational ...props/>
But what is the equivalent with vue.js?
Say I have this all in one component (did not test this one, it just for example) :
<template>
<div id="app">
<div v-for="user in users">
{{user.name}}
</div>
</div>
</template>
<script>
Vue.component({
el: '#app',
props: {
filter: "foo"
},
data: {
users: [],
},
ready: function () {
this.$http.get('/path/to/end-point?filter='+this.props.filter)
.then(function (response) {
this.users = response.data
})
}
})
</script>
How I could extract a container with just the fetch logic?
I really don't see a need for a container component. Abstract your fetch code out into a vuex action and bind your store state within the component using computed properties.
You can extend any Vue component, which will allow you to override any methods from the parent. So, you can create a base component and then extend that:
const Base = Vue.component('base-comp', {
template: "#base",
data() {
return {
name: 'foo'
}
}
});
const Child = Base.extend({
data() {
return {
name: 'bar'
}
}
});
Vue.component('child-comp', Child)
You can check out the JSFiddle here: https://jsfiddle.net/tdgxdhz9/
If you are using single file components, then it's simply a case of importing the base component and extending it, which keeps the original template in tact:
import Base from './BaseComponent.vue'
Base.extend({
// Javascript code here
})
You can use vuex-connect to create container components like in React. Here an example of project : https://github.com/pocka/vue-container-component-example
What you are looking for is Vue Mixins.
You can write a mixins file which contains your business logic and import it into your Vue components.
Link:- https://v2.vuejs.org/v2/guide/mixins.html

Categories

Resources