I am trying to make dynamic form inputs with vue.js. Here is my HTML code.
<div id="multi">
<form action="{{route('flighttickets.searchMulti')}}" method="post" class="container-fluid">
{{csrf_field()}}
<div class="row" v-for="(item, index) in items">
<div class="form-group col col-sm-3">
<select v-bind:name="inputName(index, 'from')" v-model="item.from" class="form-control" required>
<option disabled selected value=''>From</option>
#foreach($locations as $location)
<option value="{{$location->id}}">{{$location->name}}({{$location->abbreviation}})</option>
#endforeach()
</select>
</div>
<div class="form-group col col-sm-3">
<select v-bind:name="inputName(index, 'to')" v-model="item.to" class="form-control" required>
<option disabled selected value=''>To</option>
#foreach($locations as $location)
<option value="{{$location->id}}">{{$location->name}}({{$location->abbreviation}})</option>
#endforeach()
</select>
</div>
<div class="form-group col col-sm-3">
<input type="date" class="form-control" v-model="item.date" v-bind:name="inputName(index, 'date')" required>
</div>
<div class="col-auto" v-if="index >= min">
<button type="button" #click="removeItem(index)" class="close pull-left" aria-label="Close"><span aria-hidden="true">×</span></button>
</div>
</div>
<div class="row form-group" v-if="items.length <= max">
<div class="col col-sm-3 offset-sm-6">
<button type="button" #click="addItem()" class="btn btn-primary pull-right"><i class="fa fa-plus"></i></button>
</div>
</div>
<div class="row form-group">
<div class="col col-sm-3 offset-sm-6">
<button type="submit" class="btn btn-primary pull-right"><i class="fa fa-search"></i> Search</button>
</div>
</div>
</form>
</div>
The script
var multi = new Vue({
el: '#multi',
data: {
min: 2,
max: 7,
item:{from:'', to:'', date:''},
items:[ { from: '', to: '', date: '' }, {from: '', to: '', date: ''} ]
},
methods: {
removeItem: function(id) {
if(this.items.length >= this.min){
this.items.splice(id, 1);
}
},
addItem: function() {
if(this.items.length <= this.max) {
var clone = JSON.parse(JSON.stringify(this.item));
this.items.push(clone);
}
},
inputName: function(index, property) {
return "items["+index+"]["+property+"]";
}
}
});
vue.js does not do looping accordingly. According to the script, the form input should show at least 2 and without cancel button when it is less than or equal to 2. But it is not working. see the picture.
It turned out like the blade engine has some issues while compiling. I put this file in a folder together with other views. I found out that the other view had an error. Only then, this file seems to work fine. That's how i fixed it. No code changes needed to this file. Thanks you everyone for your time.
Related
Hi, I'm using Alpine.js in laravel blade and I want to build a dependent dropwdown with dynamic add new row and remove row and add new rows works fine but when I select the parent dropdown it's lost all other dependent dropdown values. Can you help to how I can get rid of ? Thanks
my-blade-file.php
{{-- add or remove dropdown seciton --}}
<div x-data="addNewWithDropdown()">
<div class="col-2">
<button class="btn bg-gradient-info custom-add-icon-btn" type="button" name="button" #click="addNewField()">
<i class="fa-solid fa-plus"></i> Add New
</button>
</div>
<div class="col-12">
<template x-for="(field, index) in fields" :key="field.id">
<div class="add-input" x-data="devicesData()">
<div class="row">
<div class="col-6">
<label class="form-label mt-0">Select Brand </label>
<select :id="'row-' + index" x-model="brand" class="form-control" name="brand[]" #change="getItems()">
<option value="-1">Select Brand</option>
#foreach ($brands as $brand)
<option value="{{ $brand->id }}">{{ $brand->brand_name }}</option>
#endforeach
</select>
</div>
</div>
<div class="row mt-2 align-items-center">
<div class="col-6">
<label class="form-label mt-0">Device Name</label>
<div class="form-group mb-0">
<select :id="'row-' + index" x-model="item" class="form-control" name="item[]">
<option value="-1">Select Device</option>
<template x-for="(item, index) in items" :key="index">
<option :value="item.id" x-text="item.item_name"></option>
</template>
</select>
</div>
</div>
<div class="col-2">
<button class="btn bg-gradient-danger custom-add-icon-btn" type="button" name="button"
#click="removeField(field)">
<i class="fa-solid fa-xmark"></i>
</button>
</div>
</div>
</template>
</div>
</div>
<script>
function addNewWithDropdown() {
return {
fields: [],
addNewField() {
this.fields.push({
id: new Date().getTime() + this.fields.length
});
},
removeField(field) {
this.fields.splice(this.fields.indexOf(field), 1);
}
}
}
function devicesData() {
return {
brand: '',
items: {},
item: '',
getItems() {
fetch(`api/my-api-route/${this.brand}`)
.then((res) => res.json())
.then((res) => {
this.items = res;
})
}
}
}
</script>
my-controller.php
<?php
public function today_buy_sales(){
$brands = Brand::orderBy('brand_name', 'asc')->get();
return view('layouts.my-blade-view', compact('brands'));
}
public function getItems($id){
$items = Item::where('brand_id', $id)->get();
return response()->json($items);
}
?>
My form sends multiple forms of (name and image). However, the last element sends a name only with the wrong 'name.' Do I need to simultaneously make multiple inserts in the database to solve this problem?
Form View
Dump of the request with wrong last element of array
Script of repeat the form
<div class="row">
<div class="col-12">
<form class="form repeater-default" method="POST"
action="{{ route('admin.cat.doCreate2') }}"
enctype="multipart/form-data">
#csrf
<input type="hidden" name="admin_id"
value="{{ auth()->guard('admin')->user()->id }}">
<div data-repeater-list="group_a">
<div data-repeater-item>
<div class="row justify-content-between">
<div class="col-md-4 col-sm-12 form-group">
<label for="Name">Name </label>
<input type="text" class="form-control" name="name[]" required
placeholder="Enter Name of Category">
</div>
<div class="col-md-4 col-sm-12 form-group">
<label for="Image">Image </label>
<input type="file" class="form-control" name="image[]">
</div>
{{-- Delete Button --}}
<div class="col-md-2 col-sm-12 form-group d-flex align-items-center pt-2">
<button class="btn btn-danger" data-repeater-delete type="button"><i
class="mdi mdi-x"></i>
Delete
</button>
</div>
</div>
<hr>
</div>
</div>
<div class="form-group">
<div class="col p-0">
<button class="btn btn-primary" data-repeater-create type="button"><i class="mdi mdi-plus"></i>
Add
</button>
</div>
<div class="col p-0">
<button class="btn btn-success" type="submit"><i class="mdi mdi-account"></i>
Done
</button>
</div>
</div>
</form>
</div>
</div>
Script
<script>
$(document).ready(function(){
$("#myInput").on("keyup", function() {
var value = $(this).val().toLowerCase();
$("#tableData tr").filter(function() {
$(this).toggle($(this).text().toLowerCase().indexOf(value) > -1)
});
});
});
</script>
first solution : inputs and their labels must be on table tag and th tag and td tag
to send right data
second solution : dont use array for inputs names like name[ ] or image[ ] :
<div class="col-md-4 col-sm-12 form-group">
<label for="Image">Image </label>
<input type="file" class="form-control"
name="image">
</div>
and receive datas like this :
$data=$request->group_a
group_a is your data-repeater-list name :
<div data-repeater-list="group_a">
and now you can put $data in foreach and use data arrays for create ...insert and anything
I am using jquery form repeater js library for repeat html but when I am trying to add elements in a nested repeater and then add a button inside the repeater then the outer repeater is also called and added on element of outer repeater.
Below is my jQuery and HTML code:
<div id="m_repeater_3">
<div class="form-group form-group-last row" id="m_repeater_3">
<div data-repeater-list="color" class="col-lg-10">
<div class="form-group row align-items-center">
<div class="col-md-3">
<div class="m-form__group--inline">
<div class="m-form__label">
<label class="m-label m-label--single">Color:</label>
</div>
</div>
</div>
</div>
<div data-repeater-item class="form-group row align-items-center">
<div class="col-md-3">
<div class="m-form__group--inline">
<div class="m-form__control">
<input type="text" class="form-control" name="color" placeholder="Color" required="required">
</div>
</div>
</div>
<div class="col-md-3">
<div class="m-form__group--inline">
<div class="m-form__control">
<input type="file" class="form-control" name="image_4" required="required">
</div>
</div>
</div>
<div class="col-md-3">
<a href="javascript:;" data-repeater-delete="" class="btn-sm btn btn-danger btn-bold">
<i class="la la-trash-o"></i>
</a>
</div>
<div id="m_repeater_2">
<div class="form-group form-group-last row" id="m_repeater_2">
<div data-repeater-list="stock" class="col-lg-10">
<div class="form-group row align-items-center">
<div class="col-md-3">
<div class="m-form__group--inline">
<div class="m-form__label">
<label class="m-label m-label--single">Size:</label>
</div>
</div>
</div>
<div class="col-md-3">
<div class="m-form__group--inline">
<div class="m-form__label">
<label class="m-label m-label--single">Stock:</label>
</div>
</div>
</div>
</div>
<div data-repeater-item class="form-group row align-items-center">
<div class="col-md-3">
<div class="m-form__group--inline">
<div class="m-form__control">
<input type="text" class="form-control" name="Size" placeholder="Color" required="required">
</div>
</div>
</div>
<div class="col-md-3">
<div class="m-form__group--inline">
<div class="m-form__control">
<input type="text" class="form-control" name="stock" placeholder="Color" required="required">
</div>
</div>
</div>
<div class="col-md-3">
<a href="javascript:;" data-repeater-delete="" class="btn-sm btn btn-danger btn-bold">
<i class="la la-trash-o"></i>
</a>
</div>
</div>
</div>
</div>
<div class="form-group form-group-last row">
<label class="col-lg-2 col-form-label"></label>
<div class="col-lg-4">
<a href="javascript:;" data-repeater-create="" class="btn btn-bold btn-sm btn-brand">
<i class="la la-plus"></i> Add
</a>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="form-group form-group-last row">
<label class="col-lg-2 col-form-label"></label>
<div class="col-lg-4">
<a href="javascript:;" data-repeater-create="" class="btn btn-bold btn-sm btn-brand">
<i class="la la-plus"></i> Add
</a>
</div>
</div>
</div>
Here is my jquery function which i am using for repeater
var FormRepeater = function() {
var demo2 = function() {
$('#m_repeater_3').repeater({
initEmpty: false,
defaultValues: {
'code': ''
},
show: function() {
$(this).slideDown("slow", function() {});
},
hide: function(deleteElement) {
$(this).slideUp(deleteElement);
}
});
}
var demo3 = function() {
$('#m_repeater_2').repeater({
initEmpty: false,
defaultValues: {
'code': ''
},
show: function() {
$(this).slideDown("slow", function() {});
},
hide: function(deleteElement) {
$(this).slideUp(deleteElement);
}
});
}
return {
// public functions
init: function() {
demo2();
demo3();
}
};
}();
var FormRepeater = function() {
var demo2 = function() {
$('#m_repeater_3').repeater({
initEmpty: false,
defaultValues: {
'code': ''
},
repeaters: [{
// (Required)`enter code here`
// Specify the jQuery selector for this nested repeater
selector: '.inner-repeater'
}],
show: function() {
$(this).slideDown("slow", function() {});
},
hide: function(deleteElement) {
$(this).slideUp(deleteElement);
}
});
}
return {
// public functions
init: function() {
demo2();
}
};
}();
I have a table that look like :
here i can define how many rows and columns i want on my table and the table get updated as i want, at here everything fine, the next step i need is to change the content of each cell and bind it to an array, i really don't know how to accomplish this, seems like contenteditable has some issues with v-model.
Another problem is that i don't know how to pass the data to my data object, should i pass it as a matrix? a array? i need to know each input for the specific row and columns, any help?
here is what i did so far:
<template>
<div>
<form class="form-horizontal">
<h2 class="text-center"> Table </h2>
<div class="form-group">
<div class="col-md-1">
<button #click="changeView('appTableStyle')" type="button" class="form-control btn btn-xs btn-warning">
<span class="glyphicon glyphicon-pencil"></span>
</button>
</div>
<label for="rows" class="control-label col-md-1">style:</label>
<div class="col-md-6">
<select class="form-control" v-model="table.tableStyle">
<option v-for="(item,key) in tableStyles" :value="item.Id">
{{ item.style }}
</option>
</select>
</div>
</div>
<div class="form-group">
<label for="rows" class="control-label col-md-2">rows:</label>
<div class="col-md-2">
<input type="number" min="1" v-model="table.rows" class="form-control" id="rows">
</div>
<label for="columns" class="control-label col-md-1">columns:</label>
<div class="col-md-2">
<input type="number" min="1" v-model="table.cols" class="form-control" id="cols">
</div>
<label for="columns" class="control-label col-md-2">How Many?:</label>
<div class="col-md-2">
<input type="number" min="1" v-model="insert" class="form-control" id="cols">
</div>
</div>
<table class="table table-responsive" style="background-color:lightGray">
<tbody>
<tr v-for="(row,idx2) in tableRows">
<td v-model="table.colsArr[idx]" :key="" class="table-success" v-for="(col,idx) in tableCols" contenteditable="true">{{idx}}</td>
</tr>
</tbody>
</table>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-9">
<div class="text-center">
<button type="submit" #click.prevent="addTable" class="btn btn-success margin-above2 btn-block">Add Table</button>
</div>
</div>
</div>
</form>
</div>
</template>
<script>
export default {
name: 'app',
data () {
return {
table: {
rows: 1,
cols: 1,
key: 'Table',
tableStyle: 1,
colsArr: []
},
insert: 1
}
},
methods: {
},
changeView: function (view) {
this.$store.commit('changeCurrentView', view)
}
},
computed: {
tableStyles () {
return this.$store.getters.getTableStyles
},
tableRows () {
return parseInt(this.table.rows)
},
tableCols () {
return parseInt(this.table.cols)
}
}
}
</script>
I made a global modal with this
<div id="GlobalModal" class="modal fade" role="dialog">
<div class="modal-dialog">
<style>
#GlobalModal .modal-body .body-content {
margin:0;
width: 100%;
}
</style>
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header" style="background:#337ab7;">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title" style="color:white">Not set...</h4>
</div>
<div class="modal-body">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary">Save</button>
<button type="button" class="btn btn-warning" data-dismiss="modal">Close</button>
</div>
</div>
</div>
and this is my button for calling the modal
<button id="new-communication" type="button" class="btn btn-info btn-sm">NEW <i class="glyphicon glyphicon-plus"></i></button>
and this is the content
<div class="hidden">
<div id="mc-communication">
<form id="loginForm" class="form-horizontal" role="form" method="POST" action="" >
<div class="form-group">
<label class="col-sm-2 control-label">Type</label>
<div class="col-sm-10">
<select class="form-control selectpicker show-tick" name="SingleSelectFieldType">
<option></option>
<option>Mobile - Private</option>
<option>Mobile - Office</option>
<option>Others</option>
</select>
</select>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Value</label>
<div class="col-sm-10 col-md-10">
<input class="form-control" type="tel" id="input-mobile-number" placeholder="" name="MobileNumberFieldType">
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label"></label>
<div class="col-sm-10">
<div class="[ form-group ]">
<input type="checkbox" checked />
<span></span><span> </span></label>
<label>Primary</label>
</div>
</div>
</div>
</form>
</div>
</div>
and this is my jQuery of calling the content to get into the modal
class.modal.js
var Modal = {
Me: $('#GlobalModal'),
Title: 'Undefined Title',
Width: { xs: '25%', sm: '40%', md: '55%', lg: '70%', xl: '85%', full: '95%' },
Show: function (params) {
this.Me.find('.modal-body').empty();
this.Me.find('.modal-title').text((this.Title == null) ? this.Title : params.Title);
if(params.Content.substr(0, 1) == '#') { //To Check if content may come from a view or a div
this.Me.find('.modal-body').append($(params.Content).clone());
} else {
this.Me.find('.modal-body').load(params.URI);
}
this.Me.find('.modal-dialog').css('width', this.Width[params.Width]);
this.Me.modal('show');
}
}
and the script to call in my view
$(document).ready(function(){
$('#new-communication').on('click', function(){
Modal.Show({
Title: 'Communication',
Content: '#mc-communication',
Width: 'sm'
});
});
});
The thing is I can see the contents inside my select, but I can't select it and I also got a checkbox there and I can't check it. I tried making a new modal that is not global, but just for the communication, and it worked, I don't know what's wrong with my code.
You will have to reinitialize the selectpicker after appending the html
if(params.Content.substr(0, 1) == '#') { //To Check if content may come from a view or a div
this.Me.find('.modal-body').append($(params.Content).clone());
// This will reinitialize selectpicker. You may need to revalidate this logic since you are appending data and not replacing.
$('.selectpicker').selectpicker();
} else {
this.Me.find('.modal-body').load(params.URI, function() {
// Initialize the selectpicker after loading the data
$('.selectpicker').selectpicker();
});
}
The reason y this is happening is, the html data is dynamic and selectpicker is not initialized in newly added html elements