Undefined array key "houseAreaTypeId"" - laravel

I am trying to store multiple row data in database. But after running foreach loop I am getting this error--Undefined array key "houseAreaTypeId""
my template--
<select
v-model="tab.selectedHouseType"
name="houseAreaTypeId[]"
>
<option
v-for="houseType in houseTypes"
:key="houseType.id"
:value="houseType.id"
>
{{ houseType.name }}
</option>
</select>
script ---
export default {
data() {
return {
tabs: [{
selectedHouseType: "",
rows: [{
selectedDecor: {},
selectedDes: "",
}],
}],
};
},
methods: {
submit(){
axios.post('/api/create-cart', {
myArray: this.tabs
}).then(({data})=>{
this.tabs.selectedHouseType = '',
this.tabs.decorTypes = ''
});
},
laravel controller--
public function createCart(Request $request)
{
if ($tabs = $request->get('myArray')) {
foreach ($tabs as $tab) {
HouseAreaCart::create([
'houseAreaTypeId' => $tab['houseAreaTypeId'],
]);
}
}
return response()->json();
}
can anyone suggest me what's wrong in my code

Where do you expect houseAreaTypeId to be coming from? This is your tabs data property:
tabs: [{
selectedHouseType: "",
rows: [{
selectedDecor: {},
selectedDes: "",
}],
}],
Your available keys then are selectedHouseType and rows. Your select's v-model binds tab.selectedHouseType with the value of houseType.id so maybe you mean to access $tab['selectedHouseType'] which will give you back that houseType ID value?

Related

Created() is not executing after delete. Inertia + Vuejs

I'm new with Vuejs and Inertia. I've created a simple dashboard using both and Laravel.
Everything works well except after delete an element, created() is not executing. Surely I'm making a mistake, but I don't found it.
Example:
Initial page:
If I press 'editar', I can edit the value.
I edit first value, 17 to 18.
And this works well. But if I want to delete the first element. The table is updated, because it depends from a prop (elements), but the elements below depend with created().
After removing:
Index.vue
<div class="mb-6 bg-white rounded-md shadow" v-if="elementsFiltrats[0].elements.length != 0">
<h2 class="pressupost_gastos_h2">General</h2>
<ul class="pressupost_gastos_ul">
<li v-for="e in elementsFiltrats[0].elements" :key="e.id" class="hover:bg-gray-100 focus-within:bg-gray-100 pressupost_gastos_li">
{{e.nom}} - {{e.valor.toFixed(2)}}€
</li>
</ul>
<h3 class="pressupost_gastos_h3">Total: {{elementsFiltrats[0].valor_total.toFixed(2)}}€ (+10%) = {{(elementsFiltrats[0].valor_total*1.10).toFixed(2)}}€</h3>
</div>
export default {
metaInfo: { title: 'Presupuestos' },
components: {
Icon,
Pagination,
SearchFilter,
},
layout: Layout,
props: {
filters: Object,
exercici: Object,
elements: Array,
comunitat: Object,
elementsagrupats: Array
},
data() {
return {
form: {
search: this.filters.search
},
elementsFiltrats: []
}
},
created(){
this.splitByType()
},
watch: {
form: {
deep: true,
handler: throttle(function() {
this.$inertia.get(this.route('pressuposts', this.exercici.id), pickBy(this.form), { preserveState: true })
}, 150),
},
'$route' : 'splitByType'
},
methods: {
reset() {
this.form = mapValues(this.form, () => null)
},
destroy(idExercici, idPressupost) {
if (confirm("Seguro que quieres eliminar el elemento del presupuesto?")) {
this.$inertia.delete(this.route('pressuposts.destroy', [idExercici, idPressupost]))
}
},
edit(idExercici, idPressupost) {
this.$inertia.get(this.route('pressuposts.edit', [idExercici, idPressupost]))
},
splitByType(){
console.log("hola")
// 0 general
// 1 escales
// 2 garatge
// valor_total
var elem = [
{
'elements' : [],
'valor_total': 0
},
{
'elements' : [],
'valor_total': 0
},
{
'elements' : [],
'valor_total': 0
}
];
this.elementsagrupats.forEach(element => {
var pos = 0;
if(element.casella === 'general'){
pos = 0;
}else if(element.casella === 'escales'){
pos = 1;
}else{
pos = 2;
}
elem[pos].elements.push({
'nom' : element['nom'],
'valor' : element['valor_total']
});
elem[pos].valor_total += element.valor_total;
});
this.elementsFiltrats = elem;
}
},
}
Controller:
Update method has:
Update code...
return Redirect::route('pressuposts', $exercici->id)->with('success', 'Element actualitzat.');
Destroy method has:
Delete code...
return Redirect::route('pressuposts', $exercici->id)->with('success', 'Element eliminat.');
Any help is appreciated.
Thanks.

Property not defined error But it is defined Vue js Laravel

I have defined the function in my vue js file but it is giving me error for nameWithLang() function Please have a look
My Form
<multiselect v-model="selected" track-by="id" label="name" :options="options" :loading="isLoading" :internal-search="false" #search-change="getData" :multiple="true" :close-on-select="false" :hide-selected="true":internal-search="false" name="books[]" :show-labels="false" :custom-label="nameWithLang"></multiselect>
My vue js file
import AppForm from '../app-components/Form/AppForm';
Vue.component('coupon-form', {
mixins: [AppForm],
data: function() {
return {
form: {
name: '' ,
description: '' ,
valid_from: '' ,
valid_till: '' ,
discount: '' ,
enabled: false,
books: [],
},
isLoading: false,
options: [],
selected: [],
}
},
methods: {
nameWithLang({ name, sku }) {
return `${name} — ${sku}`
},
getData(query){
this.isLoading = true;
axios.post('/admin/books/find/'+query)
.then((response) => {
this.options = response.data;
this.isLoading = false;
})
.catch((error) => {
this.isLoading = false;
});
},
},
watch: {
selected (newValues) {
this.form.books = newValues.map(obj => obj.id)
}
}
});
Other properties and functions are working nameWithLang is not working
It gives me error this
Property or method "nameWithLang" is not defined on the instance but referenced during render.
why not you just return the value into a variable in data, and set the function into mounted/watch instead using the function to get the value.
just for refer, you can make the script like this :
import AppForm from '../app-components/Form/AppForm';
Vue.component('coupon-form', {
mixins: [AppForm],
data: function() {
return {
form: {
name: '' ,
description: '' ,
valid_from: '' ,
valid_till: '' ,
discount: '' ,
enabled: false,
books: [],
},
isLoading: false,
options: [],
selected: [],
newName: '',
}
},
methods: {
nameWithLang({ name, sku }) {
this.newName = `${name} — ${sku}`;
},
getData(query){
this.isLoading = true;
axios.post('/admin/books/find/'+query)
.then((response) => {
this.options = response.data;
this.isLoading = false;
})
.catch((error) => {
this.isLoading = false;
});
},
},
watch: {
selected (newValues) {
this.form.books = newValues.map(obj => obj.id)
this.nameWithLang();
}
}
});
then you can make the template like this:
<multiselect v-model="selected" track-by="id" label="name" :options="options" :loading="isLoading" :internal-search="false" #search-change="getData" :multiple="true" :close-on-select="false" :hide-selected="true":internal-search="false" name="books[]" :show-labels="false" :custom-label="newName"></multiselect>
this is just another way you can make it and the way i'm understand what actually you want to do. you want to pass the name with lang value into the :custom-label right? so why not just defined one more variable and add the value into the variable. so you just need to pass the value instead the function. in v-bind it's more appropiate to pass a property instead of a method

Wrong item deleted in v-for component [choosing the right :key in v-for]

I have two components like follows:
Vue.component('comp-child', {
template: `<div>{{childData.name}}<slot></slot>{{randomNum}}</div>`,
props: {
parentData: {
}
},
data() {
return {
childData: {},
randomNum: Math.round(Math.random() * 100)
};
},
created() {
this.childData.name = this.parentData.name;
}
});
Vue.component('comp-parent', {
template: `<div><component v-for="(item, index) in arr" is="comp-child" :key="index" :parent-data="item">
<button #click="deleteItem(index)">delete</button>
</component>
</div>`,
data(){
return {
arr: [{
name:1
}, {
name:2
}, {
name:3
}, {
name:4
}, {
name:5
}]
};
},
methods: {
deleteItem(index) {
this.arr.splice(index, 1);
console.log(`${index}th element deleted! `);
}
}
});
let app = new Vue({
el: '#app'
});
<script src="https://unpkg.com/vue"></script>
<div id="app">
<comp-parent></comp-parent>
</div>
In this demo, no matter which item you click, the last item always be deleted.
I located this problem caused by key of v-for, if use 1, 2, 3, 4,.. as key, this problem occurs, but use others value as key like string, it just works fine;
template: `<div><component v-for="(item, index) in arr" is="comp-child" :key="item.key" :parent-data="item">
<button #click="deleteItem(index)">delete</button>
</component>
</div>`,
data(){
return {
arr: [{
name:1,
key: 'key1'
}, {
name:2,
key: 'key2'
}, {
name:3,
key: 'key3'
}, {
name:4,
key: 'key4'
}, {
name:5,
key: 'key5'
}]
};
},
check this fiddle: demo
Does it caused by virtual DOM? It seems VUE bind key and children components as cache, when arr changed, it just re-render components in index(1,2,3,..)'s order, if some item in arr is deleted, the length of arr decreasing cause the last one cannot be render.
Please someone explain this to me, Thanks!
When you use v-for, your key has to be some piece of data that is unique to the item in question. Index is no good because it doesn't identify the item. Just changing the key to item.name gets your example to work perfectly.
In your example, your source array was being modified correctly, but vue was reusing previously generated component instances to display the modified array, and these instances had left-over state. Vue does this for performance reasons and it's not normally a problem, but it does highlight the importance of choosing the right key.
Your problem was made worse by a couple of little things that you don't often see in nature, and that you should probably avoid... assigning parentData.name to childData.name in the created hook: because your children were getting reused, not recreated, the childData.name became stale. The same goes for the random number.
Vue.component('comp-child', {
template: `<div>{{childData.name}}<slot></slot>{{randomNum}}</div>`,
props: {
parentData: {
}
},
data() {
return {
childData: {},
randomNum: Math.round(Math.random() * 100)
};
},
created() {
this.childData.name = this.parentData.name;
}
});
Vue.component('comp-parent', {
template: `<div><component v-for="(item, index) in arr" is="comp-child" :key="item.name" :parent-data="item">
<button #click="deleteItem(index)">delete</button>
</component>
</div>`,
data(){
return {
arr: [{
name:1
}, {
name:2
}, {
name:3
}, {
name:4
}, {
name:5
}]
};
},
methods: {
deleteItem(index) {
this.arr.splice(index, 1);
console.log(`${index}th element deleted! `);
}
}
});
let app = new Vue({
el: '#app'
});
<script src="https://unpkg.com/vue"></script>
<div id="app">
<comp-parent></comp-parent>
</div>

Prop mutating warning in VUE

I got an vue-warning (which results to as an error on my end coz my code is not working) that says:
[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "editmode"
With it, tried the suggestion here but can't make it work. Below is my work:
props:{
editmode:{
type: Boolean,
default: false,
}
},
methods:{
toggleM(){
var editmode = this.editmode;
editmode = !editmode;
this.editmode = editmode;
if(editmode == false){
//dothis
}else{
//dothat
}
},
}
TEMPLATE
<template>
<div class="ui-table-container-body">
<div class="ui-table" v-if="Boolean(items.length) || Boolean(Object.keys(items).length)" v-cloak>
<ui-table-body ref="body" v-model="items"
:editmode="editmode"
>
</ui-table-body>
</div>
</div>
</template>
The line this.editmode = editmode; is the one pointed in my console, is there any way I can surpass this?
You must use a data variable as a gateway to your prop.
In your component, the code code should look like this:
props:{
editmode:{
type: Boolean,
default: false,
}
},
data: {
dataEditMode = false
},
watch: {
'editmode': {
handler: 'onEditmodeChanged',
immediate: true,
},
'dataEditMode': {
handler: 'onDataEditModeChanged'
}
},
methods:{
toggleM(){
var editmode = this.dataEditMode;
editmode = !editmode;
this.dataEditMode = editmode;
if(editmode == false){
//dothis
}else{
//dothat
}
},
onEditmodeChanged (newVal) {
this.dataEditMode = newVal
},
onDataEditModeChanged (newVal) {
this.$emit('editmodeChanged', newVal)
}
}
and the the inclusion of this component in your parent-component should look like this:
<my-component-name :editmode="editmode" #editmodeChanged="(e) => { editmode = e }"></my-component-name>
You shouldn't mutate props from the component itself. See the One Way Data Flow section of the guide. You can use a prop as the initial value, and then keep a value in the data section and mutate that:
props: {
editmode: {
type: Boolean,
default: false,
}
},
data () {
return {
emode: this.editmode,
}
},
methods: {
toggleM () {
let editmode = this.emode;
editmode = !editmode;
this.emode = editmode;
if (editmode == false) {
// dothis
} else {
// dothat
}
},
}
Demo
Vue.component('editbox', {
template: '<div>' +
'<button #click="toggleM">{{ btext }}</button>' +
'<input v-if="emode" />' +
'</div>',
props: ['editmode'],
data () {
return {
emode: this.editmode,
}
},
computed: {
btext () {
return this.emode ? "Text" : "Edit";
}
},
methods:{
toggleM() {
this.emode = !this.emode;
},
}
})
var app = new Vue({
el: '#app',
data: {
mode: true,
}
})
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<editbox :editmode="mode" />
</div>
I would send back an event to the parent so it could modify its value:
For example (not tested):
Child Component
props:{
editmode:{
type: Boolean,
default: false,
}
},
methods:{
toggleM(){
var editmode = !this.editmode;
this.$emit('changeEditMode', editmode);
if (editmode == false){
//dothis
} else {
//dothat
}
},
}
Parent
<child-component #changeEditMode="editModeChanged" :editmode="editmode"></child-component>
...
methods:{
editModeChanged(value){
this.editmode = value
},
}

Kendo Grid wouldn't sort when using Key/Value pair array object

I am using Telerik Kendo Grid; it wouldn't allow to use the sortable functionality of the table when my datasource (array) looks as below:
var myArray = [
{ Destination = { Country: "United Kingdom", AircraftTypeCount: 9 }, Origin= [ {​Country: "United States", Code: "JFK"} ] },
{ Destination = { Country: "Egypt", AircraftTypeCount: ​5 }, Origin= [ {​Country: "​Qatar", Code: "QR"} ] }]
It renders the country column fine, but when I click on the column the sorting doesn't occur. Below is my Kendo Grid (using AngularJS):
$("#myKendoTable").kendoGrid({
dataSource: {
data: myArray
},
sortable: {
mode: "multiple",
allowUnsort: true
},
columns: [
{
field: "Country",
title: "Country",
width: 300,
template: function (item) {
return item["Destination"].Country;
}
}
]
});
​
I've just sorted this out. It seems that Kendo's sorting functionality recognises basic array structure, so I had retrieve all Destinations from myArray into a separate array, and use that new array as the datasource.
I used the following method to do so (using underscoreJS):
function getDestinationsData(airlineRoutes)
{
return _.map(AirlineDestinationRoutes, function (airlineRoutes) { return airlineRoutes.Destination });
}

Resources