(Vue.js and Laravel) Array won't refresh after deleting item - laravel-5

I'm new to Vue.js, trying to create a single page blog just to get my feet wet with the vue/laravel combo, and I am stuck when it comes to deleting a "story" from the array of "stories" I am working with. I know the routes are fine because the story actually deletes, no errors are thrown, but the deleted story will remain in the array until I refresh the page. From what I've read elsewhere, the code I have implemented should update the array immediately. I have attached the relevant parts of my blade view, vue.js file, and controller. Thanks in advance!
JS (VUE)
new Vue({
el: '[vue-news]',
search: "",
data: {
stories: ''
},
ready: function() {
// GET request
this.$http.get('/app/news/get', function(data, status, request) {
// set data on vm
this.$set('stories', data);
// console.log(data);
}).error(function(data, status, request) {
// handle error
});
},
methods: {
// DELETE STORY FROM ARRAY
deleteNews: function(id, index) {
this.$http.delete('app/news/' + id + '/delete').success(function(response) {
this.stories.$remove(index);
swal("Deleted!", "Your news story has been deleted.", "success");
}).error(function(error) {
console.log(error);
swal(error);
});
}
}
});
BLADE
<section vue-news>
<div class="row news-row">
<div class="columns large-9 medium-9 small-12">
<article data-id="#{{ story.id }}" class="story panel" v-for="story in stories | filterBy search" track-by="$index">
<h1>#{{ story.title }}</h1>
<p>#{{ story.content }}</p>
<p>#{{ story.created_at }}</p>
<p>#{{ story.id }}</p>
<p>#{{ story.timestamp }}</p>
Read More...
<div class="options">
<a #click="editNews" href="#">
<i class=" edit fa fa-pencil-square-o"></i>
</a>
{{-- DELETE NEWS BUTTON --}}
<a #click.prevent="deleteNews(story.id, $index)" href="#">
<i class="delete fa fa-trash-o"></i>
</a>
</div>
</article>
</div>
<div class="columns large-3 medium-3 small-12">
<input type="text" v-model="search">
</div>
</div>
</section>
CONTROLLER
public function delete($id)
{
return response()->json(News::destroy($id));
}

The $remove method now treats the argument as an item to search for rather than an index. In other words, try this out:
Delete method:
deleteNews: function(id, story) {
this.$http.delete('app/news/' + id + '/delete').success(function(response) {
this.stories.$remove(story);
swal("Deleted!", "Your news story has been deleted.", "success");
}).error(function(error) {
console.log(error);
swal(error);
});
}
HTML section:
<a #click.prevent="deleteNews(story.id, story)" href="#">
<i class="delete fa fa-trash-o"></i>
</a>
Source: https://github.com/vuejs/vue/releases
Edit: Since you are passing the entire story item, you can actually just pass one argument and shorten the code to this:
Vue:
deleteNews: function(story) {
this.$http.delete('app/news/' + story.id + '/delete').success(function(response) {
this.stories.$remove(story);
swal("Deleted!", "Your news story has been deleted.", "success");
}).error(function(error) {
console.log(error);
swal(error);
});
}
HTML:
<a #click.prevent="deleteNews(story)" href="#">
<i class="delete fa fa-trash-o"></i>
</a>

Related

Vue 3 Axios post call works but v-model lags a step behind?

I am using Vue.js 3, Laravel and Axios to make a simple post call:
processFilters() {
self = this;
let tags = self.checkedTags.slice();
axios.post('/api/process-filters', {
filters: tags,
})
.then(function (response) {
// self.checkedTags = response.data.filters;
console.log(response.data.filters);
})
.catch(function (error) {
// handle error
console.log(error);
})
.then(function () {
// always executed
});
}
My Laravel backend function just tests if I can give back the same values to the js console:
public function processFilters(Request $request)
{
$data['filters'] = $request->input('filters');
// Return the response in json
return response()->json($data);
}
In the dev tools, my v-model checkedTags updates fine but always lags a step behind. For example, I am running processFilters() every time a checkbox is clicked:
<div v-for="(tagValue, tagKey) in tags" :key="tagKey" class="relative flex items-start py-2">
<div class="min-w-0 flex-1 text-sm">
<label :for="tagKey" class="font-medium text-gray-700 select-none">
<input v-model="checkedTags" #click="processFilters()" :id="tagKey" :value="tagKey" type="checkbox" class="focus:ring-blue-500 h-4 w-4 text-blue-600 border-gray-600 rounded">
<span class="ml-2">{{ tagKey }}</span>
</label>
</div>
<div class="ml-3 mr-1 flex items-center h-5">
{{ tagValue }}
</div>
</div>
When I click a checkbox, I get back an empty array. When two are clicked, I get an array size one, and so on?

Need guidance on how to populate a DIV using server side Ajax query then iterate with #foreach. Currently getting 'undefined variable' error

In a Laravel project I'm attempting to use Ajax to populate a DIV and then use #foreach to populate the store gallery. If possible I wanted to use a Server side content generation strategy. However, something silly is going on that I can't figure out-- I'm getting the following error:
$user_query is undefined
Make the variable optional in the blade template. Replace {{ $user_query }} with {{ $user_query ?? '' }}
How is this (#foreach ($user_query as $item)) suppose to be constructed in the blade?
routes
Route::get('/ajaxStoreRequest', 'StoreController#ajaxStoreRequest');
Route::post('/ajaxStoreRequest/post', 'StoreController#ajaxStoreRequestPost');
Here is the StoreController.php:
<?php
namespace App\Http\Controllers;
use App\Coin;
use Illuminate\Http\Request;
use App\DataTables\StoresDataTable;
use App\DataTables\StoresDataTableEditor;
use Illuminate\Support\Facades\DB;
class StoreController extends Controller
{
public function ajaxStoreRequest()
{
return view('store.index');
}
public function ajaxStoreRequestPost(Request $request)
{
$user_query= DB::table('coins')
->select('id','year', 'mint', 'series', 'rating', 'rating_group','photo_link1', 'for_sale_price')
->where('for_sale', '=', 1)
->where('sold', '=', 0)
->where('series', '=', $request->series)
->where('year', '=', $request->year)
->where('mint', '=', $request->mint)
->where('rating_group', '=', $request->rating_group)
->get();
return response()->json($user_query);
}
}
a DD($user_query); shows the following array format
Illuminate\Support\Collection {#552
#items: array:1 [
0 => {#555
+"id": 2
+"year": 1878
+"mint": "Philadelphia"
+"series": "Morgan Dollar"
+"rating": "Ungraded"
+"rating_group": "PCGS"
+"photo_link1": "editor/20200328_002220_888888966_732020162248388.jpg"
+"for_sale_price": "44"
}
]
}
Here is the Ajax script from the bottom of the store/index.blade.php
<script type="text/javascript">
$.ajaxSetup({
beforeSend: function(xhr, type) {
if (!type.crossDomain) {
xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'));
}
},
});
$(".btn-submit").click(function(e){
e.preventDefault();
var series = $("#series option:selected").val();
var year = $("input[name=year]").val();
var mint = $("#mint option:selected").val();
var rating_group = $("#rating_group option:selected").val();
var price_filter = $("input[name=price_filter]:checked").val();
$.ajax({
type:'POST',
url:'/ajaxStoreRequest/post',
data:{series:series, year:year, mint:mint, rating_group:rating_group, price_filter:price_filter},
success:function(result){
$('.collapse').collapse('show');
$('#user_query').html(result);
}
});
});
</script>
Here is the HTML further up in the store/index.blade.php
<div class="row row-deck js-gallery collapse">
<div class="user_query" id="user_query">
#foreach ($user_query as $item) <!-- THIS IS THE ERROR -->
<div class="col-md-6 col-xl-4">
<div class="block">
<div class="options-container">
#if ($item->photo_link1)
<img class="img-fluid options-item" src="storage/{{$item->photo_link1}}" style="width:300px; height:300px" alt="">
#else
<img class="img-fluid options-item" src="images/no-user-profile-picture-1200x900.jpg" style="width:300px; height:300px" alt="">
#endif
<div class="options-overlay bg-black-75">
<div class="options-overlay-content">
<a class="btn btn-sm btn-primary img-lightbox" href="gallery/{{$item->id}}">
View
</a>
<a class="btn btn-sm btn-light" href="javascript:void(0)">
<i class="fa fa-plus text-success mr-1"></i> Add to cart
</a>
</div>
</div>
</div>
<div class="block-content">
<div class="mb-2">
<div class="h4 font-w600 text-success float-right ml-1">${{$item->for_sale_price}}</div>
<a class="h4" href="be_pages_ecom_store_product.html">{{$item->year}}-{{$item->mint}}</a>
</div>
<p class="font-size-sm text-muted">{{$item->series}} ({{$item->rating}} {{$item->rating_group}})</p>
</div>
</div>
</div>
#endforeach
</div>
</div>
I'm attempting to use Ajax to populate a DIV and then use #foreach
This is fundamentally backwards. store/index.blade.php is rendered server side, so any data returned from your ajax call must be added to the DOM using JavaScript.

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.

How to use variable data after Ajax Call Success - Laravel

I created a small file manager to manage my files. On the one hand, the folder structure is shown thanks to JsTree. On the right I would like that based on the click on the left folder I was shown the files contained in that folder.
At the click an Ajax call is made which calls the selectFiles method to go through the routes. Now in the console i see the correct data, but i don't know how to use it into foreach in the blade.
AJAX:
// chiamata Ajax per selezionare files in base all'id
$('#treeview').on("select_node.jstree", function (e, data) {
var id = data.node.id;
$.ajax({
type: 'POST',
url: 'archivio_documenti/+id+/selectFiles',
data: {id:id},
success: function(data) {
console.log('Succes!',data);
},
error : function(err) {
console.log('Error!', err);
},
});
});
DocumentiController.php:
/**
* Selzionare files in base all'id della cartella
*/
public function selectFiles(Request $request){
try{
$id = $request->id;
$files = \App\Documento::where('cartella_id',$id)->get();
return response()->json(compact('files'));
}
catch(\Exception $e){
echo json_encode($e->getMessage());
}
}
Route:
Route::post('archivio_documenti/{id}/selectFiles', 'DocumentiController#selectFiles');
Update:
#foreach($files as $key => $file)
<div id="myDIV" class="file-box">
<div class="file">
{!! Form::open(['method' => 'DELETE','route' => ['documento.destroy', $file->id]]) !!}
<button type="submit" class="#" style="background: none; border: none; color: red;">
<i class='fa fa-trash' aria-hidden='true'></i>
</button>
{!! Form::close() !!}
<i class='fa fa-edit' aria-hidden='true'></i>
<input id="myInput_{{$key}}" type="text" value="{{'project.dev/'.$file->path.'/'.$file->file}}">
<i class="btnFiles fa fa-files-o" aria-hidden="true" data-id="{{$key}}"></i>
<a href="{{' http://project.dev/'.$file->path.'/'.$file->file}}">
<span class="corner"></span>
<div class="icon">
<i class="img-responsive fa fa-{{$file->tipo_file}}" style="color:{{$file->color_file}}"></i>
</div>
<div class="file-name">
{{$file->file}}
<br>
<small>Update: {{$file->updated_at}}</small>
</div>
</a>
</div>
</div>
#endforeach
OK, the foreach of yours is a bit complex, but the idea itself is simple: recreate the foreach loop from your Blade in Javascript and append the result to the DOM.
In your success callback you could e.g. do this:
$('#treeview').on("select_node.jstree", function (e, data) {
var id = data.node.id;
$.ajax({
type: 'POST',
url: 'archivio_documenti/+id+/selectFiles',
data: {id:id},
success: function(data) {
// Build the HTML based on the files data
var html = '';
$.each(data, function(i, file) {
html += '<div class="file" id="file_' + file.id + '">' + file.updated_at + '</div>';
});
// Append the built HTML to a DOM element of your choice
$('#myFilesContainer').empty().append(html);
},
error : function(err) {
console.log('Error!', err);
},
});
});
Obviously, this is simplified and you'd need to use the HTML structure you've shown us in the foreach loop above, but the idea is the same: (1) loop through your files in the data object and build the HTML structure row by row, (2) put the whole HTML block in the DOM, wherever you need it to be displayed after the user clicked on a folder.
Alternative:
If you'd like to keep the foreach loop in Blade instead of of Javascipt, you could move the loop to a separate blade:
folder_contents.blade.php
#foreach($files as $key => $file)
<div id="myDIV" class="file-box">
<div class="file">
{!! Form::open(['method' => 'DELETE','route' => ['documento.destroy', $file->id]]) !!}
<button type="submit" class="#" style="background: none; border: none; color: red;">
<i class='fa fa-trash' aria-hidden='true'></i>
</button>
{!! Form::close() !!}
<i class='fa fa-edit' aria-hidden='true'></i>
<input id="myInput_{{$key}}" type="text" value="{{'project.dev/'.$file->path.'/'.$file->file}}">
<i class="btnFiles fa fa-files-o" aria-hidden="true" data-id="{{$key}}"></i>
<a href="{{' http://project.dev/'.$file->path.'/'.$file->file}}">
<span class="corner"></span>
<div class="icon">
<i class="img-responsive fa fa-{{$file->tipo_file}}" style="color:{{$file->color_file}}"></i>
</div>
<div class="file-name">
{{$file->file}}
<br>
<small>Update: {{$file->updated_at}}</small>
</div>
</a>
</div>
</div>
#endforeach
Then, in your controller:
public function selectFiles(Request $request){
try{
$id = $request->id;
$files = \App\Documento::where('cartella_id',$id)->get();
// Save the view as string
$view = view('folder_contents.blade.php', compact('files')))->render();
// Pass the ready HTML back to Javasctipt
return response()->json(compact('view'));
}
catch(\Exception $e){
echo json_encode($e->getMessage());
}
}
you must set header for ajax
headers: {
'X_CSRF_TOKEN':'xxxxxxxxxxxxxxxxxxxx',
'Content-Type':'application/json'
},
and in Controller
public function selectFiles(Request $request){
try{
$id = $request->id;
$files = \App\Documento::where('cartella_id',$id)->get();
return response()->json($files);
}
catch(\Exception $e){
echo json_encode($e->getMessage());
}
}

go to a laravel controller using vue js's data

This is my vue
new Vue({
el: '#notificationMenu',
data: {
showModal: false,
patients: [],
duepatients: []
},
created: function(){
this.getPatients();
this.addUsers();
},
methods: {
getPatients: function(){
$.getJSON("{{route('api_patients')}}", function(patients){
this.patients = patients;
}.bind(this));
setTimeout(this.getPatients, 1000);
},
addUsers: function(){
this.$http.get('/govaccine/addUsers', '').then((response) => {
}, (response) => {
this.formErrors = response.data;
});
setTimeout(this.addUsers, 10000);
},sendSMS: function(val){
$.getJSON('sendsms/' + val,function(duepatient){
this.duepatients = duepatient;
}.bind(this));
}
}
});
and this is my html
<ul class="notifications-list" v-for="patient in patients">
<li class="item no-data">You don't have notifications</li>
<!-- use the modal component, pass in the prop -->
<modal v-if="showModal" #close="showModal = false">
<!--
you can use custom content here to overwrite
default content
-->
<h3 slot="header">custom header</h3>
</modal>
<a v-on:click="sendSMS(patient.due_date)">
<li class="item js-item " data-id="5" >
<div class="details">
<strong>#{{ patient.total}} patients</strong> are due for immunization on #{{patient.due_date}}
<span class="date">{{-- #{{patient.created_at}} --}}</span>
</div>
<button type="button" class="button-default button-dismiss js-dismiss">×</button>
</li>
</a>
</ul>
If I loop through vue js data using v-for how do i pass the data each loop in {{route('patient.show', parameter)}} so i can put a parameter on it.
or is there anyway to go to the controller and go to the other page?
yes you should use router-link. complete example here.
if I got you question wrong just tell me.

Resources