I have a laravel 5.7 application which uses VueJS 2.0 for the front end.
I have two table with many-to-many relation: commandes and produits.I am currently attempting to pass data in to my commandes table but i am getting this error:
SQLSTATE[42S22]: Column not found: 1054 Unknown column '0' in 'field list' (SQL: insert into `commande_produit` (`0`, `commande_id`, `produit_id`) values (3, , 0))
If anyone can tell me how to fix or even point me in the right direction it would be much appreciated.
The html template:
<template>
<div class="container">
<div class="row justify-content-center mt-5" v-if="$gate.isAdminOrVendeur()">
<div class="col-md-12">
<form class="" #submit.prevent="envoyer()" >
<table class="table table-bordered table-striped table-responsive">
<thead class="thead-dark">
<tr>
<th class="col-sm-4">Produit</th>
<th class="col-sm-2">Quantité</th>
<th class="col-sm-2">montant</th>
<th class="col-sm-2">Total</th>
<th class="col-sm-1"></th>
<th class="col-sm-1"></th>
</tr>
</thead>
<tbody>
<tr v-for="(commande, index) in commandes" :key="index">
<td>{{ commande.produit_id }}</td>
<td>{{ commande.quantite }}</td>
<td>{{ commande.montant }} F</td>
<td>{{ (commande.quantite * commande.montant).toFixed(2) }} F</td>
<td><a class="btn btn-info btn-block" #click="modifier(index)">Modifier</a></td>
<td><a class="btn btn-warning btn-block" #click="supprimer(index)">Poubelle</a></td>
</tr>
<tr>
<td colspan="3"></td>
<td><strong> F </strong></td>
<td colspan="2"></td>
</tr>
<tr>
<td>
<div class="form-group">
<select v-model="form.produit_id" name="produit_id" class="form-control">
<option v-for="produit in produits.data" :key="produit.id" v-bind:value="produit.id">{{ produit.designation }}</option>
</select>
</div>
</td>
<td><input type="text" class="form-control" v-model="form.quantite"></td>
<td><input type="text" class="form-control" v-model="form.montant"></td>
<td colspan="3"><a class="btn btn-primary btn-block" #click="ajouter">Ajouter</a></td>
</tr>
</tbody>
<tfoot>
<a class="button btn btn-xs btn-warning" #click="toutPoubelle">Tout à la poubelle</a>
<button class="button btn btn-xs btn-success" type="submit">Valider</button>
</tfoot>
</table>
</form>
<div class="panel panel-danger" v-show="poubelle.length">
<div class="panel-heading">Poubelle</div>
<table class="table table-bordered table-striped table-responsive">
<thead>
<tr>
<th class="col-sm-4">Produit</th>
<th class="col-sm-2">Quantité</th>
<th class="col-sm-2">montant</th>
<th class="col-sm-2">Total</th>
<th class="col-sm-1"></th>
<th class="col-sm-1"></th>
</tr>
</thead>
<tbody>
<tr v-for="(commande, index) in poubelle" :key="index">
<td>{{ commande.produit }}</td>
<td>{{ commande.quantite }}</td>
<td>{{ commande.montant }} F</td>
<td>{{ (commande.quantite * commande.montant).toFixed(2) }} F</td>
<td><a class="btn btn-success btn-block" #click="retablir(index)">Rétablir</a></td>
<td><a class="btn btn-danger btn-block" #click="eliminer(index)">Supprimer</a></td>
</tr>
</tbody>
</table>
<div class="panel-footer">
<div class="btn-group">
<a class="button btn btn-xs btn-success" #click="toutRetablir">Tout rétablir</a>
<a class="button btn btn-xs btn-danger" #click="toutEliminer">Tout supprimer</a>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
My vue instance:
<script>
export default {
data () {
return {
commandes: [],
poubelle: [],
produits: {},
form: new Form({
produit_id : '',
quantite : '',
montant: '',
})
}
},
methods: {
ajouter() {
this.commandes.push({produit_id: this.form.produit_id, quantite: this.form.quantite, montant: this.form.montant});
this.form = {};
this.commandes.sort(ordonner);
},
modifier(index) {
this.form.produit_id = this.commandes[index].produit_id;
this.form.quantite = this.commandes[index].quantite;
this.form.montant = this.commandes[index].montant;
this.commandes.splice(index, 1);
},
supprimer(index) {
this.poubelle.push(this.commandes[index]);
this.commandes.splice(index, 1);
this.poubelle.sort(ordonner);
},
retablir(index) {
this.commandes.push(this.poubelle[index]);
this.poubelle.splice(index, 1);
this.commandes.sort(ordonner);
},
eliminer(index) {
this.poubelle.splice(index, 1);
},
toutPoubelle() {
this.poubelle = this.poubelle.concat(this.commandes);
this.poubelle.sort(ordonner);
this.commandes = [];
},
toutRetablir() {
this.commandes = this.commandes.concat(this.poubelle);
this.commandes.sort(ordonner);
this.poubelle = [];
},
toutEliminer() {
this.poubelle = [];
},
loadProduits(){
//if(this.$gate.isAdminOrComptable()){
axios.get("api/produit").then(({ data }) => (this.produits = data));
//}
},
envoyer() {
axios.post('api/commande', {commande: this.commandes});
this.commandes = [];
},
},
mounted() {
this.loadProduits();
console.log('Component mounted.')
}
}
var ordonner = function (a, b) {
return (a.commande.toUpperCase() > b.commande.toUpperCase())
};
</script>
This is the commandes model:
class Commande extends Model
{
protected $fillable = ['commande'];
public function produits()
{
return $this->belongsToMany('App\Models\Produit');
}
}
and the produits model:
class Produit extends Model
{
protected $fillable = ['designation'];
public function commandes()
{
return $this->belongsToMany('App\Models\Commande');
}
}
the commande controller store() method:
public function store(Request $request)
{
$this->validate($request,[
'commande' => 'required',
]);
$commande = new Commande();
$commande->produits()->attach([$request->commande]);
$commande->save();
}
Several things may not work as expected in your code:
You are trying to attach produits on a non-existing model.
By using new Commande you are just preparing the object Commande and not yet saving it to the database. You can't attach anything on it since it doesn't have an id yet.
Solution: use Create instead of New
The method attach() is not used properly
As per the doc (https://laravel.com/docs/7.x/eloquent-relationships#updating-many-to-many-relationships) attach() is expecting an array of ids. You are trying to pass a custom array so the method won't work.
Solution: extract the Ids from your $request->command and then use attach()
Her is the final store() function:
public function store(Request $request)
{
$this->validate($request,[
'commande' => 'required',
]);
$commande = new Commande();
$commande->save();
$produitsId = array_column($request->commande, 'produit_id');
$commande->produits()->attach($produitsId);
}
Hope it help someone.
Related
Here is a small illustration of my problem.
I have an HTML table with elements and a drop down list
enter image description here
If the user clicks on in, all records with type in are displayed
enter image description here
I don't know how to do it but while searching the internet I came across this page.
When I select in, my HTML table becomes empty, it doesn't fetch the record.
Do you know why?
service.ts
#Injectable({
providedIn: 'root'
})
export class CorporateActionService {
startDate = new Date("");
prea = [{
num: "758-1184511-34",
svm: "000902988",
type: "in",
quantity: "12,00",
isin: "BE0003470755",
title: "SOLVAY BE",
},
{
num: "758-1184511-34",
svm: "000902987",
type: "out",
quantity: "11,25",
isin: "BE0152676954",
title: "AXA B FD EQUITY BELGIUM",
},
]
dataList = [{
code: 1,
name: "in"
},
{
code: 2,
name: "out"
},
]
constructor() {}
}
component.ts
export class CorporateActionComponent implements OnInit {
prea: any;
dataList: any;
brandName = {};
constructor(private service: CorporateActionService) {}
ngOnInit(): void {
this.prea = this.service.prea;
this.dataList = this.service.dataList;
this.brandName = this.dataList.brandName;
}
public selectedBrand: any;
public valueSelected() {
this.prea = this.service.prea.filter(
item => item.num === this.selectedBrand
);
}
}
component.html
<div class="home-content container ">
<h1 class="text-center pt-5 pb-3">Corporate Action</h1>
<div class="row pt-3 container">
<div class="card" style="width: 100%;">
<div class="card-body">
<div class="text-end">
<select [(ngModel)]="selectedBrand" (change)="valueSelected()">
<option>Select</option>
<option *ngFor="let item of dataList;let i = index" value="{{item.code}}" [selected]="i == 0">
{{item.name}}
</option>
</select>
</div>
<table class="table table-striped table-hover">
<thead class="thead-light">
<tr class="text-center">
<th scope="col">Client</th>
<th scope="col">N° de préavis</th>
<th scope="col">Type</th>
<th scope="col">Quantité</th>
<th scope="col">ISIN</th>
<th scope="col">Titre</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let line of prea">
<td scope="row" class="text-center">{{ line.num }}</td>
<td scope="row" class="text-center">{{ line.svm }}</td>
<td scope="row" class="text-center">{{ line.type }}</td>
<td scope="row" class="text-center">{{ line.quantity }}</td>
<td scope="row" class="text-center">{{ line.isin }}</td>
<td scope="row" class="text-center">{{ line.title }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
Here is a reproduction.
Two things:
Change the value of the options to item.name since that's how you identify them
<option *ngFor="let item of dataList;let i = index" value="{{item.name}}" [selected]="i == 0">
And filter the array by type since that's where your in and out properties are.
public valueSelected() {
this.prea = this.service.prea.filter(
(item) => item.type === this.selectedBrand
);
}
https://stackblitz.com/edit/github-jvrg8t-npq79e?file=src/app/views/dashboard/views/administration/views/corporate-action/corporate-action.component.ts
Vue 3 front-end template:
<template>
<div class="container">
<router-link to="/user/create" class="btn btn-success mt-5 mb-5">Add New</router-link>
<table class="table">
<thead>
<tr>
<th>#</th>
<th>Username</th>
<th>Email</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<button #click="sortBy('email')">Sort by email</button>
<button #click="sortBy('username')">Sort by Name</button>
<tr v-for="(item, index) in lists" :key="index">
<td scope="row">{{ index }}</td>
<td>{{ item.username}}</td>
<td>{{ item.email}}</td>
My method for sorting.
data() {
return {
lists: [], //filled in firebase by /get route
};
methods: {
sortBy(prop) {
this.lists.sort((a,b) => a[prop] < b[prop] ? -1 : 1)
},
When i try to click on a sort button by email or username i'm receiving the error sorts is not a functions.
You forgot to close the braces you opened for data() {}
data() {
return {
lists: [], //filled in firebase by /get route
};
},
methods: {
sortBy(prop) {
this.lists.sort((a,b) => a[prop] < b[prop] ? -1 : 1)
},
this is my problem, sometimes the component render the table like this.
(No problems):
(Problem):
In the 2 photo you can see the empty row generated by datatables, it means the datatable not recognize the rows and this implies the datatable options like search or pageLength dont work. What i should do?
This is my table component:
Template:
<div class="table-responsive">
<table datatable [dtOptions]="dtOptions" class="table table-hover" [ngClass]="extraClass" width="100%">
<thead>
<tr>
<th *ngFor="let column of columns">{{ column }}</th>
</tr>
</thead>
<tfoot *ngIf="footer">
<tr>
<th *ngFor="let column of columns">{{ column }}</th>
</tr>
</tfoot>
<tbody>
<ng-content></ng-content>
</tbody>
</table>
</div>
Component:
import { Component, Input, OnChanges, OnInit } from '#angular/core';
import { datatableLanguage } from "../../data/index";
#Component({
selector: 'app-table',
templateUrl: './table.component.html'
})
export class TableComponent implements OnInit, OnChanges {
#Input()
public columns: Array<string>;
#Input()
public extraClass: string;
#Input()
public footer: boolean;
public dtOptions: DataTables.Settings;
constructor() {
this.columns = new Array<string>(0);
this.extraClass = '';
this.footer = true;
this.dtOptions = {};
}
ngOnInit() {
this.checkRequiredFields();
this.dtOptions = {
"language": datatableLanguage,
"responsive": true
}
}
ngOnChanges() {
this.checkRequiredFields();
}
checkRequiredFields(): void {
if(this.columns.length <= 0)
throw new Error("Attribute 'columns' is required.");
}
}
And if you need it, the father component:
Table template part:
<app-table id="ingredientsTable" [columns]="['Nombre', 'Precio/Unidad', 'Cantidad', 'Acciones']" [footer]="ingredients.length >= 10">
<tr [class.table-danger]="ingredient.amount <= 0" *ngFor="let ingredient of ingredients">
<td class="align-middle">{{ ingredient.name }}</td>
<td class="align-middle text-center">{{ ingredient.priceByUnit | number }}</td>
<td class="align-middle text-center">{{ ingredient.amount | number }}</td>
<td>
<div class="text-center">
<div class="btn-group">
<button class="btn btn-info" (click)="changeModal(ingredient)" data-toggle="modal" data-target="#modalIngredients">
<i class="far fa-edit"></i>
</button>
<button class="btn btn-danger" (click)="deleteIngredient(ingredient)">
<i class="far fa-trash-alt"></i>
</button>
</div>
</div>
</td>
</tr>
</app-table>
I have 3 columns, one column total_column_price uses to display the calculation result of amount and device_price. How to achieve that?
The Table
{{ Form::open(['action' => 'TransactionsINController#store', 'method' => 'POST']) }}
<table class="table table-hover table-bordered">
<thead align="center">
<tr>
<th>Amount</th>
<th>Device Price</th>
<th><a href="#" class="btn btn-primary btn-sm addRow">
<i class="fa fa-plus"></i>
</a>
</th>
<th>Column Total Price</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div class="form-group">
{{ Form::number('amount[]', 'value', ['name' => 'amount[]']) }}
</div>
</td>
<td>
<div class="form-group">
{{ Form::number('device_price[]', 'value', ['name' => 'device_price[]']) }}
</div>
</td>
<td align="center">
<a href="#" class="btn btn-danger btn-sm remove">
<i class="fa fa-times"></i>
</a>
</td>
<td>
{{ Form::text('total_column_price', '') }}
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td>Total: </td>
<td style="border: none"><b class="total_price"></b></td>
<td style="border: none"></td>
</tr>
</tfoot>
</table>
{{ Form::button('<i class="far fa-save"></i> Submit', ['type' => 'submit', 'class' => 'btn btn-info'] ) }}
{{ Form::close() }}
This is the calculation I try to use. the purpose is when I make input in amount and device_price column the result will automatically appear in total_column_price.
The Script to Calculate
<script type="text/javascript">
$('tbody').delegate('.amount,.device_price','keyup',function(){
var tr=$(this).parent().parent();
var amount=tr.find('.amount').val();
var device_price=tr.find('.device_price').val();
var total_column_price=(amount*device_price);
tr.find(.total_column_price).val(total_column_price);
total_price();
});
function total_price(){
var total_price=0;
$('.total_column_price').each(function(i,e){
var total_column_price=$(this).val()-0;
total_price +=total_column_price;
});
$('.total_price').html(total_price+",00");
}
</script>
Everything seems to be good in your code the problem is way you are using the JQuery find function, you need to add quotes while entering the selector.
tr.find('.total_column_price').val(total_column_price);
Use the new event handle .on()
The .on() syntax is the new syntax that version 1.7 uses and it is meant to substitute .bind(), .delegate() and .live().
Another problem in your javascript was related to fetching the parent from on keyup in input box.
It should be like this
var tr = $(this).parent().parent().parent();
Try the code below:
$(function() {
$(document).on('keyup', 'input[name="amount[]"],input[name="device_price[]"]', function() {
var tr = $(this).parent().parent().parent();
var amount = tr.find('input[name="amount[]"]').val();
var device_price = tr.find('input[name="device_price[]"]').val();
var total_column_price = (amount * device_price);
total_price();
});
function total_price() {
var total_price = 0;
$('input[name="total_column_price[]"]').each(function(i, e) {
var total_column_price = $(this).val() - 0;
total_price += total_column_price;
});
$('.total_price').html(total_price + ",00");
}
})
I'm not sure what could be the issue here but I'm using nuxt to make a SPA app. and I'm getting an error from an already compiled piece of code I got from codepen. link to codepen
https://codepen.io/jjelic/pen/yevNLZ?editors=1010
When I try this code my my nuxt app I get an error.
I've added a file called monitor.vue in pages folder and added the html and js like so
Is this root element error common as I have never encountered it before with html and how can I avoid?
Vue.filter('currencyDisplay', {
// model -> view
read: function(val) {
if (val > 0) {
return accounting.formatMoney(val, "$", 2, ".", ",");
}
},
// view -> model
write: function(val, oldVal) {
return accounting.unformat(val, ",");
}
});
Vue.directive('sortable', {
twoWay: true,
deep: true,
bind: function() {
var that = this;
var options = {
draggable: Object.keys(this.modifiers)[0]
};
this.sortable = Sortable.create(this.el, options);
console.log('sortable bound!')
this.sortable.option("onUpdate", function(e) {
that.value.splice(e.newIndex, 0, that.value.splice(e.oldIndex, 1)[0]);
});
this.onUpdate = function(value) {
that.value = value;
}
},
update: function(value) {
this.onUpdate(value);
}
});
var vm = new Vue({
el: '#app',
data: {
rows: [
//initial data
{
qty: 5,
description: "Something",
price: 55.20,
tax: 10
},
{
qty: 2,
description: "Something else",
price: 1255.20,
tax: 20
},
],
total: 0,
grandtotal: 0,
taxtotal: 0,
delivery: 40
},
computed: {
total: function() {
var t = 0;
$.each(this.rows, function(i, e) {
t += accounting.unformat(e.total, ",");
});
return t;
},
taxtotal: function() {
var tt = 0;
$.each(this.rows, function(i, e) {
tt += accounting.unformat(e.tax_amount, ",");
});
return tt;
}
},
methods: {
addRow: function(index) {
try {
this.rows.splice(index + 1, 0, {});
} catch (e) {
console.log(e);
}
},
removeRow: function(index) {
this.rows.splice(index, 1);
},
getData: function() {
$.ajax({
context: this,
type: "POST",
data: {
rows: this.rows,
total: this.total,
delivery: this.delivery,
taxtotal: this.taxtotal,
grandtotal: this.grandtotal,
},
url: "/api/data"
});
}
}
});
<template>
<div class="panel-body" id="app">
<table class="table table-hover">
<thead>
<tr>
<th style="width: 20px;">No.</th>
<th>Description</th>
<th style="width: 80px;">Qty</th>
<th style="width: 130px;" class="text-right">Price</th>
<th style="width: 90px;">Tax</th>
<th style="width: 130px;">Total</th>
<th style="width: 130px;"></th>
</tr>
</thead>
<tbody v-sortable.tr="rows">
<tr v-for="row in rows" track-by="$index">
<td>
{{ $index +1 }}
</td>
<td>
<input class="form-control" v-model="row.description" />
</td>
<td>
<input class="form-control" v-model="row.qty" number />
</td>
<td>
<input class="form-control text-right" v-model="row.price | currencyDisplay" number data-type="currency" />
</td>
<td>
<select class="form-control" v-model="row.tax">
<option value="0">0%</option>
<option value="10">10%</option>
<option value="20">20%</option>
</select>
</td>
<td>
<input class="form-control text-right" :value="row.qty * row.price | currencyDisplay" v-model="row.total | currencyDisplay"
number readonly />
<input type="hidden" :value="row.qty * row.price * row.tax / 100" v-model="row.tax_amount | currencyDisplay"
number />
</td>
<td>
<button class="btn btn-primary btn-xs" #click="addRow($index)">add row</button>
<button class="btn btn-danger btn-xs" #click="removeRow($index)">remove row</button>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="5" class="text-right">TAX</td>
<td colspan="1" class="text-right">{{ taxtotal | currencyDisplay }}</td>
<td></td>
</tr>
<tr>
<td colspan="5" class="text-right">TOTAL</td>
<td colspan="1" class="text-right">{{ total | currencyDisplay }}</td>
<td></td>
</tr>
<tr>
<td colspan="5" class="text-right">DELIVERY</td>
<td colspan="1" class="text-right"><input class="form-control text-right" v-model="delivery | currencyDisplay"
number /></td>
<td></td>
</tr>
<tr>
<td colspan="5" class="text-right"><strong>GRANDTOTAL</strong></td>
<td colspan="1" class="text-right"><strong>{{ grandtotal = total + delivery | currencyDisplay }}</strong></td>
<td></td>
</tr>
</tfoot>
</table>
<button #click="getData()">SUBMIT DATA</button>
<pre>{{ $data | json }}</pre>
</div>
</template>
This problem is actually a very simple problem. I don't know vue, but the render method has the same limits of react's one: every component must have only one root element in its template.
This means that a situation like this isn't accepted:
<template>
<div></div>
<div></div>
</template>
But like this is correct:
<template>
<div></div>
</template>
This means that surely, somehow in the code you didn't show us, you're putting two elements as root of your template