my vue data is not changing when i click at a button - laravel

<div class="sections_container" v-for="(section, index) in sections" #click="selected_section_id = section.id">
<div class="section">
<input class="section_name" type="text" name="name" v-model="section.name" #keyup.enter="updateSection(section)">
</div>
<div class="actions">
<div style="margin-right: 10px;">
<button class="btn btn-primary" #click="updateSection(section)"type="submit"> <i class="fa fa-edit"></i></button>
</div>
<div>
<button #click="deleteSection(index)" class="btn btn-danger" type="submit"><iclass="fa fa-trash"></i></button>
</div>
</div>
</div>
The Data is abtained right and here is my data and my computed property
computed: {
selectedSection: () => {
return this.sections.filter((section) => {
console.log('selec')
return this.selected_section_id == section.id;
});
}
},
mounted() {
window.axios.get(route('allSections')).then((res) => {
this.sections = res.data;
});
},
data: function () {
return {
selected_section_id: 1,
new_section_name: '',
sections: [],
groups: [],
questions: []
}
Now When i Click the button the Seletcted_section_id should be changed but nothing happens i check the vue dev tool plugin but nothing changed unless i press the refresh button here is the two functions updateSection and deleteSection for updating and deleting the data does those functions can affect the data is not changing
updateSection(section) {
window.axios.patch(route("section.update", section.id), {name: section.name}).then((res) => {
this.sections = res.data;
const Toast = Swal.mixin({
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 3000,
timerProgressBar: true,
onOpen: (toast) => {
toast.addEventListener('mouseenter', Swal.stopTimer)
toast.addEventListener('mouseleave', Swal.resumeTimer)
}
})
Toast.fire({
icon: 'success',
title: 'Updated Successfully'
})
});
},
deleteSection(index) {
Swal.fire({
title: 'Are you sure',
text: "You won't be able to revert this",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: 'Yes, delete it'
}).then((result) => {
if (result.value) {
window.axios.delete(route('section.destroy', this.sections[index])).then(() => {
this.sections.splice(index, 1);
Swal.fire(
'Deleted',
'Your file has been deleted.',
'success'
)
})
}
})

<div class="sections_container" v-for="(section, index) in sections" #click="selected_section_id = section.id">
I assume that the reason why you are directly assigning the selected_section_id to section.id is to debug and check it straightforward. Though not sure if the section will be captured on the #click event, you can try #click="console.log(section, section.id)" if it returns anything.
Otherwise, let's try this process of elimination:
Let's revert above back to your function: <div class="sections_container" v-for="(section, index) in sections" #click="selectedSection">
#click is an event that needs user interactions, I could recommended to use it under methods, so instead of using computed, move the function under methods:
methods: {
selectedSection: () => {
return this.sections.filter((section) => {
console.log('selec')
return this.selected_section_id == section.id;
});
}
}
On your function selectedSection, this line return this.selected_section_id == section.id doesn't assign the section.id because you are using here the comparison operator == thus it doesn't do anything, instead use the regular assign operator:
return this.selected_section_id = section.id
If the above fix doesn't work, you can try going skeletal starting with the function itself, by console.log everything and check if it correctly returns anything, like in this order:
selectedSection: () => {
console.log(this.sections)
}
selectedSection: () => {
return this.sections.filter((section) => {
console.log('check the values of section: ', section, section.id);
return this.selected_section_id = section.id;
});
}
Oh, also, you could try assigning a key to your v-for directive: https://v2.vuejs.org/v2/guide/list.html#Maintaining-State

Related

Delete confirmation using SweetAlert in ASP.Net Core MVC

How to use sweetalert confirm deleting in my project
i am using asp.net MVC core 5.0
I'm trying to make delete confirmation for category. When user click this button in Index.cshtml it will show delete confirmation for delete data or not, but delete confirmation just appear for while after that data deleted without the confirmation.
Index.cshtml side =
<tr>
<th>ID</th>
<th>Kategori</th>
<th>Sil</th>
<th>Düzenle</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>#item.Id</td>
<td>#item.CategoryName</td>
<td>
<a asp-action="Delete" asp-controller="Category" asp-route-id="#item.Id" class="btn btn-danger" id="delete">Sil</a>
</td>
<td><a asp-action="Edit" asp-controller="Category" asp-route-id="#item.Id" class="btn btn-primary">Güncelle</a></td>
</tr>
}
Controller side =
public IActionResult Delete(int id)
{
var category = _unitOfWork.categoryRepo.Get(x => x.Id == id);
_unitOfWork.categoryRepo.Delete(category);
_unitOfWork.Save();
return RedirectToAction("Index");
}
js side =
<script src="/adminlte/vendor/jquery/jquery.min.js"></script>
<script src="https://unpkg.com/sweetalert/dist/sweetalert.min.js"></script>
sweetalert =
<script>
function confirm() {
swal({
title: "Are you sure?",
text: "Once deleted, you will not be able to recover",
icon: "warning",
buttons: true,
dangerMode: true,
})
.then((willDelete) => {
if (willDelete) {
swal("deleted!", {
icon: "success",
});
} else {
swal("category is safe!");
}
});
return false;
}
Merhaba/Hi İbrahim,
Change your code like below;
<td><div><form asp-action="Delete" method="post" asp-controller="Category" asp-route-id="#item.Id"><button type="button" class="btn btn-danger" onclick="return functionConfirm(this)">Delete</button></form>
</div>
</td>
and
#section Scripts{
<script>
function functionConfirm(event) {
const swalWithBootstrapButtons = Swal.mixin({
customClass: {
confirmButton: 'btn btn-success',
cancelButton: 'btn btn-danger'
},
buttonsStyling: false
})
swalWithBootstrapButtons.fire({
title: 'Emin misiniz?',
text: "Bu işlem geri alınamaz!",
icon: 'warning',
showCancelButton: true,
confirmButtonText: 'Evet, sil!',
cancelButtonText: 'Hayır, iptal',
reverseButtons: true,
timer: 3000
}).then((result) => {
if (result.isConfirmed) {
$("form").submit();
swalWithBootstrapButtons.fire({
title: 'Silindi!',
text :'Kategori silindi.',
icon: 'success',
timer:'2000'
}
)
} else if (
/* Read more about handling dismissals below */
result.dismiss === Swal.DismissReason.cancel
) {
swalWithBootstrapButtons.fire(
'İptal edildi',
'',
'error'
)
}
})
}
</script>
}

Edit default pagination in vuejs?

I handle vuejs + laravel
I Controller :
public function listData (Request $request)
{
$currentPage = !empty($request->currentPage) ? $request->currentPage : 1;
$pageSize = !empty($request->pageSize) ? $request->pageSize : 30;
$skip = ($currentPage - 1) * $pageSize;
$totalProduct = Product::select(['id', 'name'])->get();
$listProduct = Product::select(['id', 'name'])
->skip($skip)
->take($pageSize)
->get();
return response()->json([
'listProduct' => $listProduct,
'total' => $totalProduct,
]);
}
In vuejs
data() {
return {
pageLength: 30,
columns: [
{
label: "Id",
field: "id",
},
{
label: "Name",
field: "name",
},
],
total: "",
rows: [],
currentPage: 1,
};
},
created() {
axios
.get("/api/list")
.then((res) => {
this.rows = res.data. listProduct;
this.total = res.data.total;
})
.catch((error) => {
console.log(error);
});
},
methods: {
changePagination() {
axios
.get("/api/list", {
params: {
currentPage: this.currentPage,
pageSize: this.pageLength,
},
})
.then((res) => {
this.rows = res.data. listProduct;
this.total = res.data.total;
})
.catch((error) => {
console.log(error);
});
},
},
Template :
<vue-good-table
:columns="columns"
:rows="rows"
:rtl="direction"
:search-options="{
enabled: true,
externalQuery: searchTerm,
}"
:select-options="{
enabled: false,
selectOnCheckboxOnly: true,
selectionInfoClass: 'custom-class',
selectionText: 'rows selected',
clearSelectionText: 'clear',
disableSelectInfo: true,
selectAllByGroup: true,
}"
:pagination-options="{
enabled: true,
perPage: pageLength,
}"
>
<template slot="pagination-bottom">
<div class="d-flex justify-content-between flex-wrap">
<div class="d-flex align-items-center mb-0 mt-1">
<span class="text-nowrap"> Showing 1 to </span>
<b-form-select
v-model="pageLength"
:options="['30', '50', '100']"
class="mx-1"
#input="changePagination"
/>
<span class="text-nowrap"> of {{ total }} entries </span>
</div>
<div>
<b-pagination
:value="1"
:total-rows="total"
:per-page="pageLength"
first-number
last-number
align="right"
prev-class="prev-item"
next-class="next-item"
class="mt-1 mb-0"
v-model="currentPage"
#input="changePagination"
>
<template #prev-text>
<feather-icon icon="ChevronLeftIcon" size="18" />
</template>
<template #next-text>
<feather-icon icon="ChevronRightIcon" size="18" />
</template>
</b-pagination>
</div>
</div>
</template>
I am dealing with a product list that has 500,000 products. I don't want to take it out once. I want it to pull out 30 products each time, when I click on the partition, it will call to the api to call the next 30 products.. But my problem is the default pageLength is 30 products, When I choose show showing 50 products , it still shows 30 products on the page list (But I console.log (res.data.listProduct)) it shows 50 products, how do I change the default value pageLength.
Is there any way to fix this, Or am I doing something wrong. Please advise. Thanks.
Add this into computed =>
paginationOptionsComputed(){
return { enabled: true, perPage: Number(this.pageLength), }
}
And change :pagination-options="paginationOptionsComputed"
Note: actual problem is that vue-good-table expects perPage as number. If you look at the initializePagination method in here you can see this:
if (typeof perPage === 'number') {
this.perPage = perPage;
}

Laravel 7 Vue getting favorite button

is there something wrong with this part? getting this on console
app.js:38308 [Vue warn]: Unknown custom element: - did you
register the component correctly? For recursive components, make sure
to provide the "name" option.
(found in )
here is the code
<template>
<span>
<a href="#" v-if="isFavorited" #click.prevent="unFavorite(post)">
<i class="fa fa-heart"></i>
</a>
<a href="#" v-else #click.prevent="favorite(post)">
<i class="fa fa-heart-o"></i>
</a>
</span>
</template>
<script>
export default {
props: ['post', 'favorited'],
data: function() {
return {
isFavorited: '',
}
},
mounted() {
this.isFavorited = this.isFavorite ? true : false;
},
computed: {
isFavorite() {
return this.favorited;
},
},
methods: {
favorite(post) {
axios.post('/favorite/'+post)
.then(response => this.isFavorited = true)
.catch(response => console.log(response.data));
},
unFavorite(post) {
axios.post('/unfavorite/'+post)
.then(response => this.isFavorited = false)
.catch(response => console.log(response.data));
}
}
}
</script>

How to prevent vote multiple/fast clicking in Vue exploit?

I have a vote system that allows the users to vote-up or unvote.
The issue is when a user clicks on the vote button multiple times quickly. It causes the number of upvotes to go up and down in a weird way (It goes up 1,2,3 and then down to below 0, probably has to do with the Vote.vue which adds and subtracts 1's from the total votes so when clicked fast enough it causes this weirdness) .
Also, I took care to have unique questions id and user id in the vote table.
I have these simple vote/unvote methods in the QuestionsController:
/**
* Vote a question up.
*/
public function voteUp(Question $question)
{
Auth::user()->votes()->attach($question->id);
}
/**
* Vote a question down.
*/
public function voteDown(Question $question)
{
Auth::user()->votes()->detach($question->id);
}
And maybe more importantly and probably causing the issue is the Vote.vue, as you may see I add/subtract 1 to the total #votes displayed.
methods: {
voteUp(question) {
axios.post('/voteup/'+question)
.then(response => this.isVoted = true, this.votes = this.votes + 1)
.catch(response => console.log(response.data));
},
voteDown(question) {
axios.post('/votedown/'+question)
.then(response => this.isVoted = false, this.votes = this.votes - 1)
.catch(response => console.log(response.data));
}
}
How do I overcome this so users won't exploit this + make it behave more stable?
EDIT: I tried these solutions but it didn't solve the issue:
#1 - I tried #Radu Diță solution:
<vote
:votes="{{ $question->votes()->count() }}"
:question="{{ $question->id }}"
:voted="{{ $question->currentUserVoted() ? 'true' : 'false' }}"
:disabled="voteInAir"
></vote>
and the Vote.vue script:
// resources/js/components/Vote.vue
<template>
<span>
<a href="#" v-if="isVoted" #click.prevent="voteDown(question)">
<i class="fas fa-caret-up fa-3x text-primary vote-effect vote-up-effect"></i>
</a>
<a href="#" v-else #click.prevent="voteUp(question)">
<i class="fas fa-caret-up fa-3x vote-gray vote-effect"></i>
</a>
<span class="vote-count-post "><strong>{{ this.votes }}</strong></span>
</span>
</template>
<script>
export default {
props: ['question', 'voted', 'votes'],
data: function() {
return {
isVoted: '',
voteInAir: false
}
},
mounted() {
this.isVoted = this.isVote ? true : false;
},
computed: {
isVote() {
return this.voted;
},
},
methods: {
voteUp(question) {
this.voteInAir = true;
axios.post('/voteup/'+question)
.then(response => this.isVoted = true, this.votes = this.votes + 1, this.voteInAir = false)
.catch(response => console.log(response.data), this.voteInAir = false);
},
voteDown(question) {
this.voteInAir = true;
axios.post('/votedown/'+question)
.then(response => this.isVoted = false, this.votes = this.votes - 1, this.voteInAir = false)
.catch(response => console.log(response.data), this.voteInAir = false);
}
}
}
</script>
#2 - I also tried #Rijosh solution:
<vote
:votes="{{ $question->votes()->count() }}"
:question="{{ $question->id }}"
:voted="{{ $question->currentUserVoted() ? 'true' : 'false' }}"
></vote>
And this is with time interval delay which didnt work:
<template>
<span>
<a href="#" v-if="isVoted" #click.prevent="voteDown(question)">
<i class="fas fa-caret-up fa-3x text-primary vote-effect vote-up-effect"></i>
</a>
<a href="#" v-else #click.prevent="voteUp(question)">
<i class="fas fa-caret-up fa-3x vote-gray vote-effect"></i>
</a>
<span class="vote-count-post "><strong>{{ this.votes }}</strong></span>
</span>
</template>
<script>
export default {
props: ['question', 'voted', 'votes'],
data: function() {
return {
isVoted: '',
timer: null,
interval: 200,
}
},
mounted() {
this.isVoted = this.isVote ? true : false;
},
computed: {
isVote() {
return this.voted;
},
},
methods: {
voteUp(question) {
clearTimeout(this.timer);
this.timer = setTimeout(() => {
axios.post('/voteup/'+question)
.then(response => this.isVoted = true, this.votes = this.votes + 1)
.catch(response => console.log(response.data));
}, this.interval);
},
voteDown(question) {
clearTimeout(this.timer);
this.timer = setTimeout(() => {
axios.post('/votedown/'+question)
.then(response => this.isVoted = false, this.votes = this.votes - 1)
.catch(response => console.log(response.data));
}, this.interval);
}
}
}
</script>
Since you are only allowing one vote (or that is what i understand) i would not increase the upvotes directly but make kind of a system with booleans kind of like this:
<button v-on:click="activateUpVote">UpVote</button>
<button v-on:click="activateDownVote">DownVote</button>
.
.
.
data(){
return{
upVote: false,
downVote: false,
hasVoted: false
}
},
methods: {
activateUpVote(){
this.upVote = !this.upVote
if(this.upVote && (!this.hasVoted || this.downVote)){
this.downVote = false
this.hasVoted = true
this.vote('/votedown/'+this.question, this.votes + 1)
}else{
this.hasVoted = false
}
},
//downVote same as above but the other way around except for the hasVoted part
vote(route, votes) {
axios.post(route)
.then(response => votes)
.catch(response => console.log(response.data));
},
}
Try this solution
Template
<div>
<button #click="voteUp">UpVote</button>
<button #click="voteDown">DownVote</button>
</div>
Data
data: () => {
return {
timer: null,
interval: 200
}
},
Methods
methods: {
voteUp: function () {
clearTimeout(this.timer);
this.timer = setTimeout(() => {
console.log('up vote')
// your action
}, this.interval);
},
voteDown: function () {
clearTimeout(this.timer);
this.timer = setTimeout(() => {
console.log('down vote')
// your action
}, this.interval);
}
}
I'm using setTimeout and clearTimeout in the methods. This will prevent consecutive actions on the buttons. Continuous clicks will trigger only one action. The time between each click can be controlled using the interval value in the data.
You should disable the button after it was pressed and enabled it again after you get a response. This is usable for any button that you wan't to disable spamming.
In your data add a boolean for each button
data () {
return {
//other data
upVoteInAir: false
}
}
then bind your button based on the flag
<button :disabled="upVoteInAir">Up</button>
update the flag based on the http request
methods: {
voteUp(question) {
this.upVoteInAir = true
axios.post('/voteup/'+question)
.then(response => this.isVoted = true, this.votes = this.votes + 1, this.upVoteInAir = false)
.catch(response => console.log(response.data), this.upVoteInAir = false);
},
}

Vue Object is Empty

I'm using Vuejs to display data from an API to a template. I'm trying to figure out why I am not returning data for the team so I can display in for the template. Right now when I use the VueJS Chrome Extention it shows that the team is an empty object.
<div v-if="team">
<div class="row">
<div class="col-12 col-sm-12">
<div class="fw-700 pb3 mb5" style="border-bottom: 1px solid #333;">Name:</div>
<div class="mb10" style="font-size: 20px;">{{ team.name }}</div>
</div>
</div>
<script>
module.exports = {
http: {
headers: {
'X-CSRF-TOKEN': window.Laravel.csrfToken
}
},
props: [ 'id', 'editable' ],
data: function(){
return {
modalName: 'additionalInfo',
team:{
}
}
};
},
methods: {
fetchInfo: function(){
this.$http.get('/api/teams/info', { params: { id: this.id } }).then((response) => {
this.team = response.data;
});
},
},
}
}
</script>
It is empty because your method fetchInfo isn't being called, so you need to do something like this:
created () {
this.fetchInfo()
}
This will call the function fetchInfo which in turn will fetch and fill this.team

Resources