how to have Vuex mapState with computed properties in vuejs - vue.js

I'm trying to learn Vuex and tried adding the mapState with local computed property in my Vuejs 2.0 application on top of Laravel 5.4, now while adding so I'm getting following error:
Syntax Error: Unexpected token, expected , (379:32)
377 | },
378 | mapState({
> 379 | contactStore: state => state.contactStore
| ^
380 | })
381 | }
382 | }
Here is my component:
<template>
<div class="row">
<div class="table-responsive">
<table class="table table-striped">
<tbody>
<tr>
<th class="text-left">Contact Name</th>
<th class="text-left">Company Name</th>
<th class="text-left">City</th>
<th class="text-left">Email</th>
<th class="text-left">Mobile</th>
<th class="text-left">Type</th>
<th class="text-left">SubType</th>
<th class="text-left">Profile</th>
</tr>
<tr v-for="(item, index) in tableFilter">
<td class="text-left"><a #click="showModal(item)" data-toggle="modal" data-target="#showContactModal">{{ item.first_name+' '+item.last_name }}</a></td>
<td class="text-left">{{ item.company.name }}</td>
<td class="text-left">{{ item.city }}</td>
<td class="text-left">{{ item.email }}</td>
<td class="text-left">{{ item.mobile }}</td>
<td class="text-left"><span class="badge badge-info">{{ item.company.type }}</span></td>
<td class="text-left"><span class="badge badge-info">{{ item.company.sub_type }}</span></td>
<td class="text-left"><span class="badge badge-info">{{ item.profile }}</span></td>
</tr>
</tbody>
</table>
</div>
</div>
</template>
<script>
import {mapState} from 'vuex'
export default {
data(){
return {
id: '',
search: '',
model: []
}
},
computed: {
tableFilter: function () {
const searchTerm = this.search.toLowerCase();
if(this.model)
{
return this.model.filter((item) =>
(item.first_name.toLowerCase().includes(searchTerm)
|| (item.last_name !==null && item.last_name.toLowerCase().includes(searchTerm))
|| (item.company.name !==null && item.company.name.toLowerCase().includes(searchTerm))
);
}
},
mapState({
contactStore: state => state.contactStore
})
}
}
</script>
I'm trying to replace table filter computed property with the current contact_list state, how can I achieve this or I'm doing some mistake, even if I do ...mapState({}) it is showing me same type of error:
Syntax Error: Unexpected token (378:8)
376 | }
377 | },
> 378 | ...mapState({
| ^
379 | contactStore: state => state.contactStore
380 | })
381 | }
what can be done guide me. Thanks

You are getting this error because the babel is not working on your vue file. The laravel-mix library should do this for you, but if you are manually configuring the file using a webpack.config.js file, you will have to attach a babel loader to the vue loader.
I answered this question on another thread... https://stackoverflow.com/a/49581031/1718887

Related

nested v-for loop not rendering

I am trying to display a table full of Orders and the corresponding Order details in a row-like fashion. However, I've run into a bit of a conundrum. Any geniuses out there? I've tried all sorts of variations in approaching this problem but I'm stuck. Someone mentioned that perhaps using a 'computed' property would do the trick but I haven't been able to get it to work >=/. A bit of help, maybe a lot of help, would be greatly appreciated!
<div id="MyOrdersApp" class="table-responsive">
<table class="table table-striped table-bordered table-condensed">
<thead>
<tr style="color:black;font-size:2em;">
<th style="text-align:center;">Order Id</th>
<th style="text-align:center;">ProductIdsAndQuantity</th>
<th style="text-align:center;">Total Cost</th>
<th style="text-align:center;">Order Status</th>
<th style="text-align:center;">Shipment Tracking URL</th>
<th style="text-align:center;">Created Date</th>
</tr>
</thead>
<tbody>
<tr v-for="(order, i) in parsedOrders" style="background-color:snow;text-align:center;" class="align-content-center;">
<td>{{order.OrderId}}</td>
<td>
<ul>
<li v-if="order.CartLineItems != null" v-for="item in order.CartLineItems;" :key="uniqueKey">
<img :src="item.ProductImageUrl" />
<span>{{item.ProductName}} | </span>
<span>Quantity: {{item.Quantity}} | </span>
</li>
</ul>
</td>
<td style="color:black;font-size:1.5em;font-weight:bold;">{{order.TotalRevenue | currency }}</td>
<td>{{order.OrderStatus}}</td>
<td>{{order.ShipmentTrackingURL}}</td>
<td>{{order.CreatedDate | formatDate }}</td>
</tr>
</tbody>
</table>
</div>
<script>
var MyOrdersApp = new Vue({
el: '#MyOrdersApp',
data: {
parsedOrders: [],
theOrders: [],
uniqueKey: 0
},
computed: {
cartLineItems: function () {
return this.parsedOrders[0].CartLineItems;
}
},
methods: {
getMyOrders: function () {
var scope = this;
this.$http.get("https://" + location.host + "/Home/GetMyOrders").then(resp => {
if (resp.status == 200) {
this.theOrders = resp.body;
scope.setCartLineItems();
}
});
},
setCartLineItems: function () {
var scope = this;
var cartLineItems = [];
var cartDict = {};
for (var i = 0; i < this.theOrders.length; i++) {
cartDict = {};
cartLineItems = [];
cartDict = JSON.parse(this.theOrders[i].ProductIdsAndQuantity).CartLineItems;
for (var key in cartDict) {
var lineItem = JSON.parse(cartDict[key]);
cartLineItems.push(lineItem);
}
//this.allorders[i].CartLineItems = cartLineItems;
//scope.$set(this.allorders[i], 'CartLineItems', cartLineItems);
//this.theOrders[i].CartLineItems = cartLineItems;
scope.$set(this.theOrders[i], 'CartLineItems', cartLineItems);
}
this.parsedOrders = this.theOrders;
console.log("~~ Parsed Cart! ~~ ");
console.log(this.parsedOrders);
console.log(this.parsedOrders[1].CartLineItems);
}
},
mounted: function () {
var scope = this;
this.getMyOrders();
setTimeout(x => { scope.$forceUpdate(); scope.uniqueKey++; }, 1000);
}
});
</script>
How should I modify this to properly display the values in 'CartLineItems'??
Btw, parsedOrders looks like this:
If I comment out the inner v-for, the other columns display just fine and the table looks like this:
Some more background... when I fetch the orders via the $http call and the server returns the array of JSON, the ProductIdsAndQuantity property needs to be parsed as a JSON object and then set as it's own property on the order in question. The tricky part here is that the Vue component seems to not be reacting to the change in the order object array data. Hence, the need for a parsedOrders property and/or the use of scope.$forceUpdate(); or scope.uniqueKey++;. These were proposed solutions to the issue of the Vue component not re-rendering. However, these solutions are not working. So I'm stuck scratching my head...
You can't have both v-for and v-if on the same statement that's what is causing the issue. So instead try using computed in this case
<tbody>
<tr v-for="(order, i) in parsedOrders" style="background-color:snow;text-align:center;" class="align-content-center;">
<td>{{order.OrderId}}</td>
<td>
<ul>
<li v-for="(item, index) in getCartLineItems(order)" :key="index">
<img :src="item.ProductImageUrl" />
<span>{{item.ProductName}} | </span>
<span>Quantity: {{item.Quantity}} | </span>
</li>
</ul>
</td>
<td style="color:black;font-size:1.5em;font-weight:bold;">{{order.TotalRevenue | currency }}</td>
<td>{{order.OrderStatus}}</td>
<td>{{order.ShipmentTrackingURL}}</td>
<td>{{order.CreatedDate | formatDate }}</td>
</tr>
</tbody>
and in computed
computed: {
getCartLineItems() {
return order => {
if(order?.CartLineItems && order.CartLineItems.length) return order.CartLineItems;
return [];
}
}
}

Vue Component data object property's behavior not as expected [Solved]

I have an app with a child component that makes a call to an api for a player's season stats. You click on the players name and I emit click event to child from Parent component. The problem is when you click on Players name from parent all instances of the child component are revealed. I just want the one player. I thought because I have a showComponent instance for each child by toggling this.showComponent in child would get my expected behavior but no.
Code:
Parent-
methods: {
emitPlayerSeasonStatsClicked: function(event) {
const target = event.target;
EventBus.$emit("showPlayerTemplateClicked", target);
}
},
template: `
<div v-for="playerStats in props_box_game_scores[index].data.gameboxscore.awayTeam.awayPlayers.playerEntry">
<tr v-if="playerStats.player.Position === 'P'" class="d-flex" v-bind:data-player-id="playerStats.player.ID">
<td class="col-4 justify-content-center" scope="row" title="Click for Season Stats">
{{playerStats.player.FirstName}} {{playerStats.player.LastName}}
<span v-if="playerStats.stats.Wins['#text'] === '1'">(W)</span>
<span v-else-if="playerStats.stats.Losses['#text'] === '1'">(L)</span>
<span v-else-if="playerStats.stats.Saves['#text'] === '1'">(S)</span>
</td>
<td class="col-2 justify-content-center" justify-content="center">
{{playerStats.stats.InningsPitched['#text']}}</td>
<td class="col-2 justify-content-center">{{playerStats.stats.RunsAllowed['#text']}}</td>
<td class="col-2 justify-content-center">{{playerStats.stats.PitcherStrikeouts['#text']}}</td>
<td class="col-2 justify-content-center">{{playerStats.stats.EarnedRunAvg['#text']}}
</td>
</tr>
<pitcher-season-stats v-bind:props_player_id="playerStats.player.ID"></pitcher-season-stats>
</div>
Child-
cumlativeStats: Vue.component("player-season-stats", {
props: ["props_player_id"],
data: function() {
return {
Hits: "",
HR: "",
RBI: "",
BattingAvg: "",
showComponent: false
};
},
mounted: function() {
EventBus.$on("showPlayerTemplateClicked", function(data) {
this.showComponent = !this.showComponent;
});
},
methods: {
retrievePlayerStats: function(playerId) {
const url = `https://api.mysportsfeeds.com/v1.2/pull/mlb/2019-regular/cumulative_player_stats.json?player=`;
const params = {
playerstats: "AB,H,HR,RBI,AVG",
force: true
};
...
template: `
<tr class="d-flex" v-if:showComponent>
<td #click="retrievePlayerStats(props_player_id)" class="col-4 justify-content-center" scope="row">
Season Stats</td>
</td>
<td class="col-2 justify-content-center" justify-content="center">
{{ Hits }}</td>
<td class="col-2 justify-content-center">{{ HR }}</td>
<td class="col-2 justify-content-center"> {{ BattingAvg }}</td>
<td class="col-2 justify-content-center">{{ RBI }}</td>
</tr>
` // End template
})
Any suggestions welcome. Sorry for the formatting.
**
Updated Working Solution:
**
Parent:
methods: {
emitPlayerSeasonStatsClicked: function($event) {
let playerId = $event.target.dataset.playerId;
EventBus.$emit("showPlayerTemplateClicked", playerId);
}
}
....
<table #click="emitPlayerSeasonStatsClicked($event)" class="table table-striped table-bordered table-hover table-sm collapse" v-bind:class="'multi-collapse-' + index">
<tr v-if="playerStats.stats.AtBats['#text'] > 0" class="d-flex">
<td class="col-4 justify-content-center" :data-player-id='playerStats.player.ID' scope="row" title="Click for Season Stats">
{{playerStats.player.FirstName}} {{playerStats.player.LastName}} ({{playerStats.player.Position}})</td>
Child:
mounted: function() {
EventBus.$on(
"showPlayerTemplateClicked",
this.onShowPlayerTemplateClicked
);
},
methods: {
onShowPlayerTemplateClicked: function(playerId) {
if (playerId === this.props_player_id) {
this.loading = true;
this.showComponent = !this.showComponent;
this.retrievePlayerStats(playerId);
}
},
template: `
<transition name="fade">
<tr class="d-flex" v-if="showComponent">
<td v-if="!loading" class="col-4 justify-content-center" scope="row">
Season Stats</td>
</td>
<td class="col-2 justify-content-center" justify-content="center">
{{ Hits }}</td>
<td class="col-2 justify-content-center">{{ HR }}</td>
<td class="col-2 justify-content-center"> {{ BattingAvg }}</td>
<td class="col-2 justify-content-center">{{ RBI }}</td>
</tr>
</transition>
` // End template
})
};
The code provided doesn't actually call emitPlayerSeasonStatsClicked but I assume that's supposed to go on the <td> that includes the name.
If you write the click listener like this:
<td
class="col-4 justify-content-center"
scope="row"
title="Click for Season Stats"
#click="emitPlayerSeasonStatsClicked(playerStats.player.ID)"
>
Then include the id as part of the event emitted by the event bus:
emitPlayerSeasonStatsClicked: function(playerId) {
EventBus.$emit("showPlayerTemplateClicked", playerId);
}
Listening for this in the mounted would be:
mounted: function() {
EventBus.$on("showPlayerTemplateClicked", this.onShowPlayerTemplateClicked);
},
with method:
methods: {
onShowPlayerTemplateClicked: function(playerId) {
if (playerId === this.props_player_id) {
this.showComponent = !this.showComponent;
}
}
}
Assuming the player ids are unique that should be enough to get it working.
However...
The choice of an event bus to pass data to a child seems a poor one. There are several ways this could be done. One way would be to only create it when it's showing (external v-if). Another would be to use props. Yet another would be to use refs to call a method on the child.
I don't understand how your code ever toggled anything. The this value for the listener in mounted will not be the component. I've fixed that by moving it to a method, which Vue will bind correctly. Another reason to move this to a method is that it allows you to remove the listener when the component is destroyed.
v-if:showComponent is not a thing. I assume that should be v-if="showComponent".
Your <tr> elements seem to be immediate children of <div> elements. That isn't correct HTML for tables.

How can I iterate over array data and create new row for every new data in vue?

I have a stream data that I call through axios.get and the resposne.data is a json with one sensor's data like ,{"Temperature":"56"}, with this I use to create a row in vue template.The resposne.data is assigned to array but its not appending rows ,the data in table are getting changed.
This is the template part
<template>
<div class="container">
<h1>Tabular Data</h1>
<table class="table table-striped table-bordered" >
<thead>
<tr>
<th class="text-center">Time</th>
<th class="center">Device Parameter</th>
<th class="center">Magnitude</th>
<th class="right">Unit</th>
</tr>
</thead>
<tbody>
<tr v-for="data in Tabular" :key="data">
<td> {{new Date().toString()}} </td>
<td class="test-left">Temperature</td>
<td class="text-center"> {{data.toString()}} </td>
<td class="test-left">C</td>
</tr>
<!-- <td>{{data_alias.Humidity}}</td>
<td>{{data_alias.Pressure}}</td> -->
</tbody>
</table>
</div>
</template>
<script>
/* eslint-disable */
import axios from 'axios';
export default {
name: 'tabular',
data() {
return {
Tabular:[ ],
}
},
mounted() {
setInterval(()=>{
axios.get('http://localhost:3000/data')
.then((response)=>{
console.log(response.data);
this.Tabular=response.data;
})
.catch((error)=>{
console.log(error);
});
},2000);//I used set interval to get data from stream constantly
},
}
</script>
are you sure Tabular fill at one even?
I think no, because this.Tabular=response.data; ;
this.Tabular is undefined ;
try this
var that = this;
axios.get('http://localhost:3000/data')
.then((response)=>{
console.log(response.data);
that.Tabular=response.data;
})
.catch((error)=>{
console.log(error);
});
That is because you are replacing the content of this.Tabular. You should loop through your response data and, considering response.data is an array of rows, use
response.data.forEach((row) => { this.Tabular.push(row) })

How to remove ??? characters on database query result with Laravel

I am have an issue that sounds new and don't know what is happening. I am retrieving data from database with Laravel eloquent.
In my controller:
public function index()
{
$suppliers = Supplier::all();
return response()->json($suppliers);
}
Its working just fine, the problem is the result object however is appearing as shown below with leading ???. All query results in the entire project is rendering just this way. I have tried to trim the project witn trim() but I realize this wont work on object.
����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������[{"id":1,"first_name":"Ronald","last_name":"Wekesa","mobile_number":"0717245218","work_phone":"07140000","phone_code":254,"fax":null,"email":"email#yaho.com","postal_address":"P.o
Box
323","town":"Kitale","zip":30200,"phisical_address":"Kiminini","company":"Wafutech","created_at":"2018-03-05
11:52:30","updated_at":"2018-03-05
11:52:30"},{"id":2,"first_name":"Ronald","last_name":"Wekesa","mobile_number":"0725645544","work_phone":"070025400","phone_code":2....
when I render the result in my vuejs front end as shown below I am getting blank loop, I mean the loop runs but with empty bullet list. I am suspecting this might have something with this fun behavior.
//My View component
<template>
<div>
<h3>Suppliers</h3>
<div class="row">
<div class="col-md-10"></div>
<div class="col-md-2">
<router-link :to="{ name: 'create-supplier'}" class="btn btn-primary">Add Supplier</router-link>
</div>
</div><br />
<table class="table table-hover table-striped table-responsive">
<thead>
<tr>
<td>First Name</td>
<td>Last Name</td>
<td>Company</td>
<td>Mobile Phone</td>
</tr>
</thead>
<tbody>
<tr v-for="supplier in suppliers">
<td>{{ supplier.first_name }}</td>
<td>{{ supplier.last_name }}</td>
<td>{{ supplier.company }}</td>
<td>{{ supplier.mobile_number }}</td>
<td><router-link :to="{name: 'edit-supplier', params: { id: supplier.id }}" class="btn btn-primary">Edit</router-link></td>
<td><button class="btn btn-danger" v-on:click="deleteSupplier(supplier.id)">Delete</button></td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
export default {
name:'displayAsset',
data(){
return{
suppliers: []
}
},
created: function()
{
this.fetchSuppliers();
},
methods: {
fetchSuppliers()
{
let uri = 'http://localhost/ims/public/api/suppliers';
this.axios.get(uri).then((response) => {
this.suppliers = response.data;
});
},
deleteSupplier(id)
{
let uri = `http://localhost/ims/public/api/suppliers/${id}`;
this.suppliers.splice(id, 1);
this.axios.delete(uri);
}
}
}
</script>
I have tried to re-install laravel but no difference. I have also re-installed my xampp server with the latest version but wan't lucky either. What is causing this and how can I resolve it. Thanks in advance.

Removing a row from a table with VueJS

In Vue how do you remove a row from a table when the item is deleted?
Below is how I am rendering the table
<tbody>
<tr v-for="item in items">
<td v-text="item.name"></td>
<td v-text="item.phone_number"></td>
<td v-text="item.email"></td>
<td><button #click="fireDelete(item.id)">Delete</button></td>
</tr>
</tbody>
Below is an excerpt from my Vue component.
data() {
return {
items: []
}
},
methods: {
fireDelete(id) {
axios.delete('/item/'+id).then();
}
},
mounted() {
axios.get('/item').then(response => this.items = response.data);
}
The axios.get work and so does the axios.delete, but the fronend doesn't react so the item is only removed from the table after a page refresh. How do I get it to remove the relevant <tr>?
I've managed to work out a nice way. I pass the index to the fireDelete method and use the splice function. Works exactly how I wanted.
<tbody>
<tr v-for="(item, index) in items" v-bind:index="index">
<td v-text="item.name"></td>
<td v-text="item.phone_number"></td>
<td v-text="item.email"></td>
<td><button #click="fireDelete(item.id, index)">Delete</button></td>
</tr>
</tbody>
fireDelete(id, index) {
axios.delete('/item/'+id).then(response => this.organisations.splice(index, 1));
}
I had the same trouble as this question. So maybe someone will find this usefull.
For the button use:
v-if="items.length > 1" v-on:click="fireDelete(index)"
And the fireDelete function:
fireDelete: function (index) {
this.photos.splice(index, 1);
}
You can try to modify your #click="fireDelete(item.id)" part to a custom method #click='deleteData(items, item.id)'
and do something like:
methods: {
deleteData (items, id) {
this.items = null // These parts may not
this.fireDelete(id) // match your exact code, but I hope
} // you got the idea.
}
and your template can do just:
<tbody>
<tr v-for="item in items" v-if='items'>
<td v-text="item.name"></td>
<td v-text="item.phone_number"></td>
<td v-text="item.email"></td>
<td><button #click="deleteData(item, item.id)">Delete</button></td>
</tr>
</tbody>