Regards, I have a problem I am using the SmartAdmin DataTable and I need to put three buttons in a column to edit, view and delete an element I have already put the buttons in a Column, but until now I have not been able to make them respond to the even to click.
Thank you.
enter image description here
This is the code I have in my ngOnInit
this.options = {
dom: "Bfrtip",
ajax: (data, callback, settings) => {
this._usuarioService.readUsuarios()
.subscribe((data) => {
callback({
aaData: data
})
})
},
columns: [
{ data: 'id' },
{ data: 'persona.nombre' },
{ data: 'persona.apellido' },
{ data: 'persona.correo' },
{ data: 'rol.nombre' },
{ data: 'persona.sede.nombre' },
{defaultContent: '<center><button class=\'btn btn-success btn-xs\'(click)=\'leerUnUsuario(id)\'> Ver </button> ' +
'<button class=\'btn btn-info btn-xs\' (click)=\'actualizarUsuario(id)\'> Editar </button> ' +
'<button class=\'btn btn-danger btn-xs\' (click)=\'eliminarUsuario(id)\'> Borrar </button></center>' },
]
};
Already solved, I received help from Alain D'EURVEILHER and everything is already very well.
ngOnInit() {
this.options = {
dom: "Bfrtip",
ajax: (data, callback, settings) => {
this._usuarioService.readUsuarios()
.subscribe((data) => {
callback({
aaData: data
})
})
},
columns: [
{ data: 'id' },
{ data: 'persona.nombre' },
{ data: 'persona.apellido' },
{ data: 'persona.correo' },
{ data: 'rol.nombre' },
{ data: 'persona.sede.nombre' },
{
render: (data, type, fullRow, meta) => {
return `
<button class="btn btn-xs btn-success accion-ver-usuario" data-usuario-id="${fullRow.id}">ver</button>
<button class="btn btn-xs btn-info accion-editar-usuario" data-usuario-id="${fullRow.id}">editar</button>
<button class="btn btn-xs btn-danger accion-borrar-usuario" data-usuario-id="${fullRow.id}">borrar</button>
`;
}
}
]
};
ngAfterViewInit(){
document.querySelector('body').addEventListener('click', (event)=> {
let target = <Element>event.target;// Cast EventTarget into an Element
if (target.tagName.toLowerCase() === 'button' && $(target).hasClass('accion-ver-usuario')) {
this.verUsuario(target.getAttribute('data-usuario-id'));
}
if (target.tagName.toLowerCase() === 'button' && $(target).hasClass('accion-editar-usuario')) {
this.editarUsuario(target.getAttribute('data-usuario-id'));
}
if (target.tagName.toLowerCase() === 'button' && $(target).hasClass('accion-borrar-usuario')) {
this.borrarUsuario(target.getAttribute('data-usuario-id'));
}
});
}
verUsuario(userId){
console.log("user displayed:", userId);
}
editarUsuario(userId){
console.log("user edited:", userId);
}
borrarUsuario(userId){
console.log("Delete user", userId, "?");
}
Related
Action in controller
Method GetById is the same as the Find method and EntityUpdate == Update
public IActionResult CategoryStatus(int id)
{
var data = cm.GetById(id);
if (data.CategoryStatus)
{
data.CategoryStatus = false;
}
else
{
data.CategoryStatus = true;
}
cm.EntityUpdate(data);
return RedirectToAction("Index");
}
I want to call this action from razor view with ajax, can anyone help , thanks.
I add some parts of razor view just in case
<a href="/Admin/Category/CategoryStatus/#item.CategoryID"
class="btn btn-outline-success btn-sm"
onclick="return functionConfirm(this)">
Aktivləşdir
</a>
<script>
function functionConfirm(event) {
swal({
title: 'Are you sure?',
text: "You will not be able to recover this item!",
type: 'warning',
showCancelButton: true,
cancelButtonText: 'No',
cancelButtonClass: 'btn btn-danger',
showConfirmButton: true,
confirmButtonText: 'Yes',
confirmButtonClass: 'btn btn-success'
}, function (isConfirm) {
if (isConfirm) {
$.ajax({//I need your help here
type: "GET",
url: '/Admin/Category/CategoryStatus',
success: function (msg) {
console.log(msg);
},
error: function (req, status, error) {
console.log(msg);
}
});
return true;
} else {
return false;
}
});
return false;
}
Change your code like below:
//add this....
<a data-id="#item.CategoryID"
class="btn btn-outline-success btn-sm"
onclick="return functionConfirm()">
Aktivləşdir
</a>
#section Scripts
{
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/sweetalert/1.1.3/sweetalert.min.css" integrity="sha512-gOQQLjHRpD3/SEOtalVq50iDn4opLVup2TF8c4QPI3/NmUPNZOk2FG0ihi8oCU/qYEsw4P6nuEZT2lAG0UNYaw==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/sweetalert/1.1.3/sweetalert.min.js" integrity="sha512-7VTiy9AhpazBeKQAlhaLRUk+kAMAb8oczljuyJHPsVPWox/QIXDFOnT9DUk1UC8EbnHKRdQowT7sOBe7LAjajQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script>
function functionConfirm() {
swal({
title: 'Are you sure?',
text: "You will not be able to recover this item!",
type: 'warning',
showCancelButton: true,
cancelButtonText: 'No',
cancelButtonClass: 'btn btn-danger',
showConfirmButton: true,
confirmButtonText: 'Yes',
confirmButtonClass: 'btn btn-success'
}, function (isConfirm) {
var id = $(event).data("id"); //add....
if (!isConfirm) return;
$.ajax({
type: "GET",
url: '/Admin/Category/CategoryStatus/'+id, //modify...
success: function (msg) {
window.location.href="/xxx/Index"
},
error: function (req, status, error) {
console.log(msg);
}
});
});
}
</script>
}
<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
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);
},
}
I have the next table..
The IDOP column is a key that I'm using for connect in my app instead of email... I would like to be able for filter the IDOP of each user... So the user should only be able to see the rows with
of its corresponding IDOP, how could I filter only his IDOP?
this is the function of my datatable
$('#user_contactabilidadasesor').DataTable({
processing: true,
"scrollX": true,
//serverSide: true,
ajax: {
url: "{{ route('contactabilidadasesor.index') }}",
},
columns: [
{
data: 'idop',
name: 'l.idop',
className: 'uniqueClassName'
},
{
data: 'idop_asesor',
name: 'idop_asesor',
searchable: false, render: function ( data, type, row ) {
if (data == null){ return ''; }else{return (row['idop_asesor'] + ' ' + row['ape_asesor'])};
},
className: 'uniqueClassName'
}
],
});
And this is my query
public function index(Request $request)
{
if($request->ajax())
{
$data = DB::table('tbl_lista_contactabilidad as a')
->select('a.id','a.postventaatcs_id')
->leftjoin('tbl_equipo_postventaatcs as h','h.id','=','a.postventaatc_id')
->leftjoin('users as l','l.id','=','h.asesor_id')
->select(array('a.id','l.name as idop_asesor','l.apellido as ape_asesor','l.idop'));
return DataTables::of($data)
->addColumn('action', function($data){
$button = '<button type="button" name="edit" id="'.$data->id.'" class="edit btn btn-primary btn-sm">Auditar</button>';
//$button .= ' <button type="button" name="edit" id="'.$data->id.'" class="delete btn btn-danger btn-sm">Delete</button>';
return $button;
})
->rawColumns(['action'])
->make(true);
}
return view('contactabilidadasesor');
}
For filtering you have to use ->where('IDOP', auth()->user()->IDOP) (for single user) of ->whereIn('IDOP', [array of filtering idops]) for multiple IDOPs
So im creating a basic tasklist where i want to set them done, when the <li>is clicked. When it's clicked i want that a class is added to the <li> thats clicked. i could not figure this out with the docs so i hope someone could help me out :D
The code i already have:
<transition-group name="list">
<li class="list-item list-group-item" v-for="(task, index) in list" :key="task.id" v-on:click="finishTask(task.id)" >
#{{ task.text }}
<button #click="removeTask(task.id)" class="btn btn-danger btn-xs pull-right">Delete</button>
</li>
</transition-group>
</ul>
</div>
// get the csrf token from the meta
var csrf_token = $('meta[name="csrf-token"]').attr('content');
export default {
data() {
return {
list: [],
taskInput: {
id: '',
text: ''
}
};
},
// So the tasks will show when the page is loaded
created() {
this.allTasks();
},
methods: {
// get all the existing tasks
allTasks() {
axios.get('tasks').then((response) => {
this.list = response.data;
});
},
// create a new task
createTask() {
axios({
method: 'post',
url: '/tasks',
data: {
_token: csrf_token,
text: this.taskInput.text,
},
}).then(response => {
this.taskInput.text = '';
this.allTasks();
});
},
// remove the tasks
removeTask(id) {
axios.get('tasks/' + id).then((response) => {
this.allTasks();
});
},
finishTask(id) {
axios({
method: 'post',
url: 'tasks/done/' + id,
data: {
_token: csrf_token,
data: this.taskInput,
},
}).then(response => {
this.allTasks();
});
}
}
}
I know how i should do this with jquery but not with vue js, i hope this aint a to stupid question :D
You can bind css classes and styles, add a Boolean done property to your note object with default value of false, when you click the note change its done property to true. here is an example
new Vue({
el:"#app",
data:{
notes: [
{ text: "First note", done:false },
{ text: "Second note", done:false },
{ text: "Third note", done:false },
{ text: "Fourth note", done:false },
{ text: "Fifth note", done:false }
]
},
methods:{
finishNote(note){
// send your api request
// then update your note
note.done = true
}
}
})
.done{
background-color:green;
}
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.13/dist/vue.min.js"></script>
<div id="app">
<ul>
<li v-for="note in notes" :class="{done:note.done}" #click="finishNote(note)">{{note.text}}</li>
</ul>
</div>
You can use the event argument. Which is automatically provided on your on click method.
onListClicked(event) {
event.target.className += " myClass";
}
Here I did a demo for you: https://jsfiddle.net/6wpbp70g/