Insert and Create data from data array with existing data - laravel

I''m new to laravel and vue.js. Need help :)
I have 2 tables. The purchase and the remittance. In my project, I have already STORED some data to the purchase table. But the remittance_id has no data yet (unsigned null by default and data should be stored after update).
So, for example. I checked table row 1 and table row 2. ((2) [{…}, {…}, ob: Observer] array list)
And by clicking my GENERATE REMITTANCE BUTTON, It will show a MODAL. And I have to input 2 fields (sample_date and sample_no) and it will automatically update the remittance_id
ON SUBMIT, my purchase table the 2 selected rows will now have updated remittance_id of 1(for example). my remittance table will now create sample_date, sample_no and remittance_id(1)
<vs-prompt
#accept="generateRemittance"
:is-valid="validDate"
:active.sync="popupRemit"
accept-text= "Generate" title="Generate" color="warning">
<div class="con-exemple-prompt">
Enter details to <b>continue</b>.
<div class="vx-col w-full mb-base">
<div class="vx-row mb-6">
<div class="vx-col sm:w-1/3 w-full">
<span>SAMPLE DATE:</span>
</div>
<div class="vx-col sm:w-2/3 w-full">
<vs-input name="sample_date" class="w-full" type="date" v-model="sample_date"/>
</div>
</div>
<div class="vx-row mb-6">
<div class="vx-col sm:w-1/3 w-full">
<span>SAMPLE NO</span>
</div>
<div class="vx-col sm:w-2/3 w-full">
<vs-input name="sample_no" class="w-full" v-model="sample_no"/>
</div>
</div>
</div>
</div>
</vs-prompt>
<vs-button #click="addRemit" type="filled" color="primary" icon-pack="feather" icon="icon-download">GENERATE REMITTANCE</vs-button>
my method
methods: {
addRemit(){
this.popupRemit = true
},
generateRemittance () {
this.$nextTick().then(result => {
if (result) {
this.$vs.loading();
axios
.post("/api/my/sample/url/", this.form)
.then(res => {
this.$vs.loading.close();
Fire.$emit('AfterSave');
})
.catch(error => {
this.$vs.loading.close();
this.$vs.notify({
title: "Error",
text: error.response.data.errors || error.response.data.message,
iconPack: "feather",
icon: "icon-alert-circle",
color: "danger"
});
});
}else {
this.$validator.reset()
this.$validator.resume()
console.log(this.$validator.errors);
this.$vs.notify({
title: "Error",
text: this.$validator.errors,
iconPack: "feather",
icon: "icon-alert-circle",
color: "danger"
});
}
});
},
thanks.

Seems like your purchase table belongsTo the remittance table, so you'll want to create the remittance model first and save the purchase model after, you can do this with a tap:
tap(Remittance::create($request->only(['sample_no', 'sample_date'])), function (Remittance $remittance) use ($purchase) {
$remittance->purchase()->save($purchase);
});
Here tap is giving us access to the created Remittance model in the callback, where we're then saving the one-to-one relationship.

Related

Is there a way to NOT refresh the Page after Updating the data? Laravel 8 and Vue

How can I not refresh or reload the page after updating the data?
I am using Modal to edit the data but the problem is the page still refresh after saving it, is there another way around to fix this concern?
<button class="btn btn-warning" #click="edit(item)"><i class="fa fa-edit"></i></button>
Modal:
<div class="modal fade" id="editModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Employee Edit</h5>
</div>
<div class="modal-body">
<div class="form-group">
<label>Name</label>
<input type="text" class="form-control" v-model="formEdit.name">
</div>
......
Script: (edit is used to show the data and update is used to update the data)
edit(item){
const vm = this;
vm.formEdit.name = item.name;
vm.formEdit.address = item.address;
vm.formEdit.position = item.position;
this.selectedId = item.id;
$('#editModal').modal('show');
},
update(){
const vm = this;
axios.put(`/employees/${vm.selectedId}`, this.formEdit)
.then(function (response){
alert('Employee Updated')
location.reload();
})
.catch(function (error){
console.log(error);
});
}
This is for Laravel 8 and Vue
employees component:
props: ['employee'],
data() {
return {
employeeList: this.employee,
form:{
name: null,
address: null,
position: null
},
formEdit:{
name: null,
address: null,
position: null
},
selectedId: null
}
}
Please next time add all relevant code to let us know what are you trying to achieve.
First of all, please note that data provided from props should not be mutated because of an anti-pattern. Said that you have to create a deep copy within your component in order to change its content.
Assuming that you are working in just 1 component, where you have your table listing all employees, you can do something like this.
<template>
<div>
<table>
<tr v-for="item in employeeList" :key="item.id">
<td>name: {{ item.name }}</td>
<td>address : {{ item.address }}</td>
<td>position : {{ item.position }}</td>
<td><button class="btn btn-warning" #click="edit(item)"><i class="fa fa-edit"></i></button></td>
</tr>
</table>
<div class="modal fade" id="editModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Employee Edit</h5>
</div>
<div class="modal-body">
<div class="form-group">
<label>Name</label>
<input type="text" class="form-control" v-model="form.name">
</div>
</div>
<div class="modal-footer">
<button class="btn btn-success" #click="update()">Save</button>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
employee: Array
},
data: () => ({
employeeList: [],
form: {}
}),
mounted () {
// Since changing a props is anti-pattern, we use a local data which can be manipulated
this.employeeList = [...this.employee]
},
methods: {
edit(item){
// Assign the clicked item to form data
this.form = item
$('#editModal').modal('show')
},
update(){
axios.put(`/employees/${this.form.id}`, this.form)
.then(function (response){
alert('Employee Updated')
// Find the employee index in employeeList array
const updatedEmployee = response.data
const index = this.employeeList.findIndex(x => x.id === updatedEmployee.id)
// If employee is found, then proceed to update the array object by using ES6 spread operator
if (index !== -1) {
this.employeeList = [...this.employeeList.slice(0, index), { ...updatedEmployee}, ...this.employeeList.slice(index + 1)]
}
})
.catch(function (error){
console.log(error)
})
}
}
}
</script>
Code is self-explanatory, but just in case I will clarify a little bit:
Because we can not mutate the props employee, we copy the array to local data by using the ES6 spread operator in mounted() hook.
When you click the button to edit an employee, you assign the item to the form data. Now you have the form with all employee data to be shown/changed anywhere.
Once success API response, since you are updating, you look for the array object and replace the whole array to avoid reactivity issues. In case you are adding a new one, you just can push it by doing this.employeeList.push(updatedEmployee)
EDIT: please note that the above code is a suggestion about how to work with a clean code.
Anyway, right to your question, you can update your array in your axios response by doing
.then(function (response){
alert('Employee Updated')
// Find the employee index in employeeList array
const updatedEmployee = response.data
const index = this.employeeList.findIndex(x => x.id === updatedEmployee.id)
// If employee is found, then proceed to update the array object by using ES6 spread operator
if (index !== -1) {
this.employeeList = [...this.employeeList.slice(0, index), { ...updatedEmployee}, ...this.employeeList.slice(index + 1)]
}
})
.catch(function (error){
console.log(error)
})
during update remove
location.reload();
and add the below code
$('#editModal').modal('hide');
To display data follow the procedure, update data receive from response:
updateStudent(){
axios.put('update_student',{
id:this.id,
name:this.editname,
email:this.editemail,
phone:this.editphone,
})
.then(response=>console.log(response));
axios.get('all_students')
.then(response => {
this.data = response.data;
});
},
You can display the updated data like the below code:
<tr v-for="row in data">
<th scope="row">1</th>
<td>{{ row.name }}</td>
</tr>
Let's create an item in data to assign the value we get from props. Next, let's assign props data to the created element.
The page refresh issue will be resolved.

Toggle form in nested v-for loop in VueJS

I have a list of nested comments. Under each comment, I'd like to add a "reply" button that, when click, show a reply form.
For now, everytime I click a "reply" button, it shows the form. But the thing is, I'd like to show only one form on the whole page. So basically, when I click on "reply" it should close the other form alreay opened and open a new one under the right comment.
Edit :
So I was able to make some slight progress. Now I'm able to only have one active form opening on each level of depth in the nested loop. Obviously, what I'm trying to do now is to only have one at all.
What I did was emitting an event from the child component and handle everything in the parent component. The thing is, it would work great in a non-nested comment list but not so much in my case...
Here is the new code:
In the parentComponent, I have a handleSelected method as such:
handleSelected (id) {
if(this.selectedItem === id)
this.selectedItem = null;
else
this.selectedItem = id;
},
And my childComponent:
<template>
<div v-if="comment">
<div v-bind:style=" iAmSelected ? 'background: red;' : 'background: none;' ">
<p>{{ comment.author.name }}<br />{{ comment.created_at }}</p>
<p>{{ comment.content }}</p>
<button class="button" #click="toggle(comment.id)">Répondre</button>
<button class="button" #click="remove(comment.id)">Supprimer</button>
<div v-show="iAmSelected">
<form #submit.prevent="submit">
<div class="form-group">
<label for="comment">Votre réponse</label>
<textarea class="form-control" name="comment" id="comment" rows="5" v-model="fields.comment"></textarea>
<div v-if="errors && errors.comment" class="text-danger">{{ errors.comment[0] }}</div>
</div>
<button type="submit" class="btn btn-primary">Envoyer</button>
<div v-if="success" class="alert alert-success mt-3">
Votre réponse a bien été envoyée !
</div>
</form>
</div>
</div>
<div v-if="comment.hasReply">
<div style="margin-left: 30px;">
<comment v-for="comment in comments"
:key="comment.id"
:comment="comment" #remove-comment="remove"
:is-selected="selectedItem" #selected="handleSelected($event)">
</comment>
</div>
</div>
</div>
</template>
<script>
import comment from './CommentItem'
export default {
name: 'comment',
props: {
isSelected: Number,
comment: {
required: true,
type: Object,
}
},
data () {
return {
comments: null,
fields: {},
errors: {},
success: false,
loaded: true,
selectedItem: null,
}
},
computed: {
iAmSelected () {
return this.isSelected === this.comment.id;
}
},
methods: {
remove(id) {
this.$emit('remove-comment', id)
},
toggle(id) {
this.$emit('selected', id);
},
handleSelected(id) {
if(this.selectedItem === id)
this.selectedItem = null;
else
this.selectedItem = id;
},
},
mounted(){
if (this.comment.hasReply) {
axios.get('/comment/replies/' + this.comment.id)
.then(response => {
this.comments = response.data
})
}
}
}
</script>
Thanks in advance for your help!

How to empty input fields from a pop-up window after submitting - Vue - laravel?

My page exist of a table where I can add new rows. If you want to add a new row a pop-up window appear where the new values can be added.
This new data is then saved to the database after submitting. If I again want to add a new row the input fields, they should be cleared.
The method I use, is working but isn't very clear.
Note: My code shows only a part of the input fields, to make it more clear. My pop-up window actually contains 20 input fields.
I would like to clear them all at once instead of clearing them one by one (like I am doing now).
Because I am already doing this for defining the v-model, pushing the new data to the database directly on the page and via post axios request.
Is there a cleaner way to do this?
Thanks for any input you could give me.
This is my code:
html part
<div class="col-2 md-2">
<button class="btn btn-success btn-sx" #click="showModal('add')">Add New</button>
<b-modal :ref="'add'" hide-footer title="Add new" size="lg">
<div class="row" >
<div class="col-4">
<b-form-group label="Category">
<b-form-input type="text" v-model="newCategory"></b-form-input>
</b-form-group>
</div>
<div class="col-4">
<b-form-group label="Name">
<b-form-input type="text" v-model="newName" placeholder="cd4"></b-form-input>
</b-form-group>
</div>
<div class="col-4">
<b-form-group label="Amount">
<b-form-input type="number" v-model="newAmount" ></b-form-input>
</b-form-group>
</div>
</div>
<div class="row" >
<div class="col-8">
</div>
<div class="col-4">
<div class="mt-2">
<b-button #click="hideModal('add')">Close</b-button>
<b-button #click="storeAntibody(antibodies.item)" variant="success">Save New Antibody</b-button>
</div>
</div>
</div>
</b-modal>
</div>
js part
<script>
import { async } from 'q';
export default {
props: ['speciedata'],
data() {
return {
species: this.speciedata,
newCategory: '',
newName: '',
newAmount:'',
}
},
computed: {
},
mounted () {
},
methods: {
showModal: function() {
this.$refs["add"].show()
},
hideModal: function(id, expId) {
this.$refs['add'].hide()
},
addRow: function(){
this.species.push({
category: this.newCategory,
name: this.newName,
amount: this.newAmount,
})
},
storeSpecie: async function() {
axios.post('/specie/store', {
category: this.newCategory,
name: this.newName,
amount: this.newAmount,
})
.then(this.addRow())
// Clear input
.then(
this.newName = '',
this.newCategory = '',
this.newAmount = '',
)
.then(this.hideModal('add'))
},
}
}
</script>
in your data of vuejs app , you have to set one object for displaying modal data like modalData then to reset data you can create one function and set default value by checking type of value using loop through modalData object keys
var app = new Vue({
el: '#app',
data: {
message:"Hi there",
modalData:{
key1:"value1",
key2:"value2",
key3:"value3",
key4:5,
key5:true,
key6:"val6"
}
},
methods: {
resetModalData: function(){
let stringDefault="";
let numberDefault=0;
let booleanDefault=false;
Object.keys(this.modalData).forEach(key => {
if(typeof(this.modalData[key])==="number"){
this.modalData[key]=numberDefault;
}else if(typeof(this.modalData[key])==="boolean") {
this.modalData[key]=booleanDefault;
}else{
// default type string
this.modalData[key]=stringDefault;
}
});
}
}
})
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<div id="app">
{{modalData}}
<br/>
<button #click="resetModalData">Reset Modal Data</button>
</div>
update : in your case :
data:{
species: this.speciedata,
modalData:{
newCategory: '',
newName: '',
newAmount:''
}
},
and after storing data :
storeSpecie: async function() {
axios.post('/specie/store', {
category: this.newCategory,
name: this.newName,
amount: this.newAmount,
})
.then(()=>{
this.addRow();
this.resetModalData();
this.hideModal('add')
}
},
In native Javascript you get the reset() method.
Here is how it is used :
document.getElementById("myForm").reset();
It will clear every input in the form.

How to the Clicked image ID in Vuejs

I loop and display the images from the database. Every image has a unique ID and I want to get the ID when an image is clicked.
<div v-for="kudo in catkudo" style="width:20%;float:left;display:block;height:80px;">
<div class="kudos_img" style="">
<img style="width:40%" v-bind:value="kudo.id" v-on:click="select($event)" v-model="kudocat" :src="'/kudosuploads/badges/'+kudo.image" alt="">
<p>{{ kudo.catname }}</p>
</div>
</div>
addKudoPost: function(profile_id){
var formkudodata = new FormData();
formkudodata.append('kudodescription', this.kudodescription);
formkudodata.append('kudouser', this.selected);
formkudodata.append('kudoimage', this.kudocat);
axios.post('/addNewsFeedKudoPost', formkudodata)
.then(response=>{
if(response.status===200){
this.posts = response.data.posts;
this.birthdays = response.data.birthdays;
console.log(this.kudodescription);
console.log(this.selected);
$('#post-box')[0].innerHTML = "";
this.newsfeedPostImages();
}
})
.catch(function (error) {
console.log(error);
});
},
I need to get the ID and assign it to a variable when the image is clicked.
Your select method has to have kudo.id as parameter.
<template>
<div v-for="kudo in catkudo" style="width:20%;float:left;display:block;height:80px;">
<div class="kudos_img" style="">
<img style="width:40%" :value="kudo.id" #click="select(kudo.id)" v-model="kudocat" :src="'/kudosuploads/badges/'+kudo.image" alt="">
<p>{{ kudo.catname }}</p>
</div>
</div>
</template>
export default {
methods: {
select (id) {
console.log(id, 'is selected');
}
}
}
v-on:click="select($event, kudo.id)"
If your kudo indeed has an id, then this will work. And you need to modify select to take in said id.

Owl carousel spits out a single item instead of a carousel

I am trying to make a carousel that shows a list of new tutors in a specific area from latest first. I am using laravel 5.6, vue.js and owl carousel.
Below I am using axios to retrieve from the database, and call owl-carousel
<script>
export default {
props: {
areaId: null,
},
data () {
return {
NewTutors: {}
}
},
methods: {
getNewTutor () {
var that = this;
axios.get( '/' + this.areaId + '/home/new').then((response) => {
that.NewTutorss = response.data;
})
.catch(error => {
console.log(error)
this.errored = true
});
}
},
mounted () {
this.getNewTutor();
}
}
$(document).ready(function() {
$('#NewHustles').owlCarousel();
});
</script>
and here and try and loop through each new tutor in a carousel.
<div class="owl-carousel owl-theme owl-loaded" id="NewTutors">
<div class="owl-stage-outer">
<div class="owl-stage">
<div class="owl-item" v-for="NewTutor in NewTutors>
<div class="card">
<div class="card-header">
{{NewTutor.name}}
</div>
<div class="card-body">
<div>
{{NewTutor.area.name}}
</div>
<div>
Image goes here
</div>
<div>
{{NewTutor.user.first_name}}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
I get all the cards, with the correct data passed through, but instead of a single row carousel, I get a big blob of cards that move as if there was only one item. I have tried Vue.nexttick, and playing around with a few other things, but nothing seems to work quite right.
Thank you for your help.

Resources