How to render component data after page load on click - vue.js

I am using vue js with laravel. I want to reload my data according to date on click.
My data from api is get according to date but in front it is not change
Here is under my app.js code
var socket = new Vue({
el: "#enrollment-app",
components: {
barChart
},
data: {
privateChannleData: null,
exam_type: null,
exam_id: null,
response_exam_data: [],
response_lap_data: [],
response_btn_list: [],
student_list: [],
lineChartData: {
lables: [],
options: [],
dataset: []
}
},
created() {
if (document.getElementById("exam_type"))
this.exam_type = document.getElementById("exam_type").value;
if (document.getElementById("exam_id"))
this.exam_id = document.getElementById("exam_id").value;
if (this.exam_type != null && this.exam_id != null)
this.getEnrollmentStatus();
},
methods: {
getEnrollmentStatus: function(date="null") {
var self = this;
var data_set = [];
var params = {
exam_type: document.getElementById("exam_type").value,
exam_id: document.getElementById("exam_id").value,
date:date,
};
console.log(params);
axios
.post("/api/get_enrollment_data", params)
.then(function(response) {
self.response_exam_data = response.data.data;
//console.log(self.response_exam_data.students[0]);
self.response_exam_data.students[0].forEach(function(ii, vv) {
self.student_list.push(ii);
});
self.response_btn_list=self.response_exam_data.articles[0];
self.lineChartData.dataset = {
labels: [
"Total Enrollment",
"Not Submitted",
"Submitted",
"Total Pass",
"Total Fail"
],
datasets: [
{
label: "Enrollment Data",
backgroundColor: "#f87979",
data: [
parseInt(self.response_exam_data.total_enrollment),
parseInt(self.response_exam_data.not_submitted),
parseInt(self.response_exam_data.submitted_count),
parseInt(self.response_exam_data.total_pass),
parseInt(self.response_exam_data.total_fail)
]
}
]
};
self.lineChartData.options = {
scales: {
yAxes: [
{
ticks: {
beginAtZero: true
}
}
]
},
responsive: true,
maintainAspectRatio: true
};
})
.catch(function(error) {
alert("Error. Try again after sometime.");
});
}
},
});
Here is under my html code.
<div id="enrollment-app">
<button v-for="(button, key) in response_btn_list" type="button" v-on:click="getEnrollmentStatus({{ button }})" class="btn btn-success btn-icon left-icon mr-10" :date="button">lap #{{ key+1 }} </button>
<div class="user-data">
<span class="name block capitalize-font">#{{student.name}}</span>
<span class="time block" style="width:400px;"> Status:- <span class="txt-primary">#{{student.status_text}} </span> Rank:- <span class="txt-primary">#{{student.My_rank}}</span> Time Taken:- <span class="txt-primary">#{{student.timeTaken}}</span><br/>
Result:- <span class="txt-primary">#{{student.final_result}}</span>
Total Marks:- <span class="txt-primary">#{{student.total_marks}}</span>
Obtained Marks:- <span class="txt-primary">#{{student.obtained_marks}}</span>
</span>
<div :class="student.status"></div>
<div class="clearfix"></div>
</div>
</div>
My resultant data on page load
image on laad data
My resultant data after click on button
data after click button
I only want to render data in front end..

Related

How to make a list containing checkboxes attached to object in a v-for directive switch state safely (W/O switching other checkboxes in the list)?

I'm trying to make a client-side-only todolist that uses VueJS (2.x). Here is my HTML:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>To-do List</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.2.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-Zenh87qX5JnK2Jl0vWa8Ck2rdkQ2Bzep5IDxbcnCeuOxjzrPF/et3URy9Bv1WTRi" crossorigin="anonymous">
</head>
<body>
<div id="app">
<h1>To-do List</h1>
<h2>Completed Tasks!</h2>
<ul>
<li v-for="item in complete">{{ item.description }}<input type="checkbox" :checked="item.done" #change="item.done = false"></li>
</ul>
<h2>Uncompleted Tasks!</h2>
<ul>
<li v-for="item in uncomplete">{{ item.description }}<input type="checkbox" :checked="item.done" #change="item.done = true"></li>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue#2.7.13/dist/vue.js"></script>
<script type="module" src="scripts/app.js"></script>
</body>
</html>
Then in scripts/app.js I did this:
'use strict'
let app = new Vue({
el : "#app",
data : {
tasks: [
{ description: 'Say Hello', done: true },
{ description: 'Review Code', done: false },
{ description: 'Read Emails', done: false },
{ description: 'Reply to Emails', done: false },
{ description: 'Wash The Dishes', done: true },
{ description: 'Stop Working', done: true },
]
},
computed : {
complete : function() {
return this.tasks.filter(task => task.done === true);
},
uncomplete : function() {
return this.tasks.filter(task => task.done === false);
}
}
});
My issue is simple: when I change the state of a checkbox (checking it or unchecking it) in a given list, the checkbox that directly follows it switches state as well.
I can't figure out why this happens and how to fix it. If one can tell me why this happens (so that I don't have to come back here whenever I have a misbehaving v-for/switch-state) as well as how to fix it, that would be great!
first of all. You'd better use Function in data instead of Object, or it may cause an update error.
Since Function is accepted only when used in a component definition.
// wrong
data: {
tasks: []
}
// correct
data() {
return {
task: []
}
}
You may not change the computed attribute directly which only has a Computed Getter in default. If you want to handle the computed attribute, give a Computed Setter to it.
// wrong
computed: {
complete(){
return this.tasks.filter(task => task.done === true);
},
}
// right
computed: {
complete: {
get() {
return this.tasks.filter(task => task.done === true);
},
set(value) {
this.task.forEach((task, index) => {
let matched = value.find(({ description }) => description === task.description);
if(matched) {
this.task[index] = matched;
}
});
}
}
}
you can't bind the value via v-for, because vue2 can't recognize the changes in the array.
<!-- wrong -->
<li
v-for="item in complete">
{{ item.description }}
<input
type="checkbox"
:checked="item.done"
#change="item.done = false">
</li>
<!-- correct -->
<li
v-for="(item, index) in complete">
{{ item.description }}
<input
type="checkbox"
:checked="item.done"
#change="complete[index].done = false">
</li>
new Vue({
el: "#app",
data() {
return {
tasks: [
{ description: 'Say Hello', done: true },
{ description: 'Review Code', done: false },
{ description: 'Read Emails', done: false },
{ description: 'Reply to Emails', done: false },
{ description: 'Wash The Dishes', done: true },
{ description: 'Stop Working', done: true },
]
};
},
computed : {
complete: {
get() {
return this.tasks.filter(task => task.done === true);
},
set(value) {
this.task.forEach((task, index) => {
let matched = value.find(({ description }) => description === task.description);
if(matched) {
this.task[index] = matched;
}
});
}
},
uncomplete: {
get() {
return this.tasks.filter(task => task.done === false);
},
set(value) {
this.task.forEach((task, index) => {
let matched = value.find(({ description }) => description === task.description);
if(matched) {
this.task[index] = matched;
}
});
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<h1>To-do List</h1>
<h2>Completed Tasks!</h2>
<ul>
<li
v-for="(item, index) in complete">
{{ item.description }}
<input
type="checkbox"
v-model="complete[index].done">
</li>
</ul>
<h2>Uncompleted Tasks!</h2>
<ul>
<li
v-for="(item, index) in uncomplete">
{{ item.description }}
<input
type="checkbox"
v-model="uncomplete[index].done">
</li>
</ul>
</div>

Button component does not receive DataTable props

I am trying to add a button to my vuejs DataTable. I created a Button component and I can add it as a column in my DataTable, but I can't send it through props. I do not have full knowledge of vue, for sure I am doing something wrong.
Vue.component('edit-button', {
template: `
<button class="btn btn-xs btn-primary" #click="goToUpdatePage">Edit</button>
`,
props: ['data'],
methods: {
goToUpdatePage: function(){
alert(data)
}
}
});
export default {
data() {
return {
numeroPagina: 1,
tiposNatureza: [],
utisMoveis: [],
list: [],
filtros: {
dataInicial: new Date().toISOString().split('T')[0],
dataFinal: new Date().toISOString().split('T')[0],
selectedUtisMoveis: [],
selectedStatus: [],
selectedTipoNatureza: [],
selectedTipoPesquisa: ''
},
tabela: {
columns: [
{
// <a data-toggle="modal" data-target="#ExemploModalCentralizado">${row.DESCRICAO}</a>
label: 'Descrição', representedAs: function (row) {
if (row.DESCRICAO) return `<a data-toggle="modal" data-target="#ExemploModalCentralizado">${row.DESCRICAO}</a> <button onclick="alertMe('TESTE')">TESTE</button>`
else return '<b>Sem informação</b>'
}, interpolate: true
},
{
label: 'Quantidade', representedAs: function (row) {
return `<p><span class="label label-primary" style="font-size: 17px">${row.QTD}</span></p>`
}, interpolate: true
},
{
label: 'Action',
component: 'edit-button',
data: 'row',
component_data: {
path: 'contact',
action: 'update'
}
}
],
rows: []
}
}
}
<div class="row">
<div class="col-lg-12">
<div class="ibox float-e-margins">
<div class="ibox-title">
<h2 v-if="quantidadeDeRegistros > 0">Foram encontrado(s) {{ quantidadeDeRegistros }}
resultado(s)</h2>
</div>
<div class="ibox-content no-padding" style="font-size: 15px">
<datatable :columns="tabela.columns" :data="tabela.rows"></datatable>
<datatable-pager v-model="numeroPagina" type="abbreviated" :per-page="8"></datatable-pager>
</div>
</div>
</div>
</div>
I need to create a button that takes the information from the selected row (row.DESCRIPTION) and sends it to a method, where I will do some dealing in a modal. Thank you very much in advance.
Try using this to reference the component scope.
alert(this.data)
And remove:
props: ['data'],
You do not want a passed in prop called data. You want the component's defined data property

vue select all checkboxes with value generated by computed methods

My page has a Select All checkbox at the top where upon clicking it, it should have checked all the checkboxes. Here's my code:
<div class="columns bottom-border">
<div class="column">Student</div>
<div><a v-on:click="revokePoints()">Revoke</a><br/><input type="checkbox" v-model="selectAll">Select All</div>
</div>
<div class="columns" v-for="(behavior) in sortBehaviors(behaviorList)" :key="behavior._id">
<div class="column">{{ behavior.studentID.firstName }} </div>
<div class="column is-1"><center><input type="checkbox" :value="setCheckedValue(behavior.dataType,behavior._id,behavior.studentID._id,behavior.actionDate)" :id="setCheckedValue(behavior.dataType,behavior._id,behavior.studentID._id,behavior.actionDate)" v-model="checkedIDs"></center></div>
</div>
data() {
return {
positiveName: '',
behaviorList: [],
checkedIDs: [],
selected: []
};
},
computed:{
selectAll: {
get: function () {
return this.behaviorList ? this.selected.length == this.behaviorList.length : false;
},
set: function (value) {
var mySelected = [];
let self = this;
if (value) {
this.behaviorList.forEach(function (behavior) {
var getDataType = behavior.dataType
var getID = behavior._id
var getStudentID = behavior.studentID._id
var getActionDate = behavior.actionDate
var getGeneratedID = self.setCheckedValue(getDataType,getID,getStudentID,getActionDate);
mySelected.push(getGeneratedID);
});
}
self.selected = mySelected;
console.log("self selected")
console.log(self.selected)
}
}
},
methods: {
setCheckedValue(dataType,id,studentID,actionDate){
return "1:" + dataType + "|2:" + id + "|3:" + studentID + "|4:" + actionDate
},
revokePoints(){
var pointsToRevoke = this.checkedIDs;
console.log("pointsToRevoke")
console.log(pointsToRevoke)
}
When I click on the Select All checkbox, console will display that self.selected will have the id of all the checkboxes. But the issue is the checkbox for all the values displayed are not checked...
It is difficult to help because your code is not completed. But I would approach that a bit differently. I hope this codepen can help you.
const list = [
{ id: 1, name: 'New York', checked: true },
{ id: 2, name: 'Sydney', checked: false },
{ id: 3, name: 'London', checked: false },
{ id: 4, name: 'Chicago', checked: true }
]
new Vue({
el: '#app',
data() {
return {
list,
isAllChecked: false
};
},
methods: {
checkAll: function() {
this.list = this.list.map(city => ({ ...city,
checked: !this.isAllChecked
}))
this.isAllChecked = !this.isAllChecked
}
},
computed: {
getAllCheckedIDs: function() {
return this.list.filter(city => city.checked).map(city => city.id)
},
getNotAllCheckedIDs: function() {
return this.list.filter(city => !city.checked).map(city => city.id)
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<ul>
<li v-for="city in list" :key="city.id">
<label>
{{city.name}}
<input type="checkbox" v-model="city.checked" />
</label>
</li>
</ul>
<button #click="checkAll">Check all</button>
<br/>
<div>Checked IDs: {{getAllCheckedIDs}}</div>
<div>Not Checked IDs: {{getNotAllCheckedIDs}}</div>
</div>

Vue 2 Emit selected data back to parent component

Struggling to sort out how to get a selected value from a Typeahead component to pass back to the parent component. I'm allowing the user to search from a variety of data to link a record to a post. Once the user clicks one of the typeahead drop-down records, I pass the item to the sendlink method - I've checked that the data passes ok. When I do the emit using the selected-link event, I'm not getting the data in the parent component.
PostList.vue
<template>
<div>
<div v-if='posts.length === 0' class="header">There are no posts yet!</div>
<form action="#" #submit.prevent="createPost()" class="publisher bt-1 border-fade bg-white" autocomplete="off">
<div class="input-group">
<input v-model="post.content" type="text" name="content" class="form-control publisher-input" placeholder="What's the lastest?" autofocus>
<span class="input-group-btn">
<button type="submit" class="btn btn-primary">Post</button>
</span>
</div>
<span class="publisher-btn file-group">
<i class="fa fa-camera file-browser"></i>
<input type="file">
</span>
</form>
<div #click="doit" v-on:selected-link="onSelectedLink">{{ modellink.name }}</div>
<typeahead
source="/api/typeahead"
placeholder="Link Post to Trip, Business, etc"
filter-key="title"
:start-at="3">
</typeahead>
<post v-for="post in posts"
:key="post.id"
:post="post"
#post-deleted="deletePost($event)">
</post>
</div>
</template>
<script>
var axios = require("axios");
import post from './PostItem.vue';
import typeahead from './Typeahead.vue';
export default {
components: {
post,
typeahead
},
props: ['postableId', 'postableType', 'model'],
data: function() {
return {
modellink: {
"name": "n/a",
"description": "",
"id": null,
"model": "n/a"
},
post: {
id: 1,
content: "",
edited: false,
created_at: new Date().toLocaleString(),
user: {
id: 1,
name: '',
}
},
posts: [
{
id: 1,
content: "",
edited: false,
created_at: new Date().toLocaleString(),
user: {
id: 1,
name: '',
}
}
]
};
},
created() {
this.fetchPostsList();
},
methods: {
onSelectedLink: function (talink) {
alert(JSON.stringify(talink, null, 4));
this.link = talink
},
doit() {
alert(JSON.stringify(this.modellink, null, 4));
},
fetchPostsList() {
if( this.postableId ) {
axios.get('/api/' + this.postableType + '/' + this.postableId + '/posts').then((res) => {
this.posts = res.data;
});
} else {
axios.get('/api/post').then((res) => {
//alert(JSON.stringify(res.data[0], null, 4));
this.posts = res.data;
});
}
},
createPost() {
axios.post('api/post', {content: this.post.content, user_id: Laravel.userId, vessel_id: Laravel.vesselId })
.then((res) => {
this.post.content = '';
// this.post.user_id = Laravel.userId;
// this.task.statuscolor = '#ff0000';
this.edit = false;
this.fetchPostsList();
})
.catch((err) => console.error(err));
},
deletePost(post) {
axios.delete('api/post/' + post.id)
.then((res) => {
this.fetchPostsList()
})
.catch((err) => console.error(err));
},
}
}
</script>
Typeahead.vue
<template>
<div>
<input
v-model="query"
#blur="reset"
type="text"
class="SearchInput"
:placeholder="placeholder">
<transition-group name="fade" tag="ul" class="Results">
<li v-for="item in items" :key="item.id">
<span #click="sendlink(item)">
<strong>{{ item.name }}</strong> - <small>{{ item.model }}</small><br>
<small>{{ item.description }}</small>
</span>
</li>
</transition-group>
<p v-show="isEmpty">Sorry, but we can't find any match for given term :( </p>
</div>
</template>
<script>
var axios = require("axios");
export default {
name: 'Typeahead',
props: {
modellink: {
type: Object,
required: false
},
source: {
type: [String, Array],
required: true
},
filterKey: {
type: String,
required: true
},
startAt: {
type: Number,
default: 3
},
placeholder: {
type: String,
default: ''
}
},
data() {
return {
items: [],
query: '',
taitem: ''
}
},
computed: {
lookup() {
if(this.query.length >= this.startAt) {
axios.get(this.source + '/' + this.query).then((res) => {
this.items = res.data;
return res.data;
});
}
},
isEmpty() {
if( typeof this.lookup === 'undefined' ) {
return false
} else {
return this.lookup.length < 1
}
}
},
methods: {
sendlink: function (taitem) {
this.$emit('selected-link', taitem);
},
reset() {
this.query = ''
}
}
}
</script>
In your PostList.vue, move the v-on:selected-link="onSelectedLink" from the div to typeahead like below. When emitting an event from child to parent, the listener on the parent needs to be on the child component tag for it to work.
<div #click="doit">{{ modellink.name }}</div>
<typeahead
source="/api/typeahead"
placeholder="Link Post to Trip, Business, etc"
filter-key="title"
:start-at="3"
v-on:selected-link="onSelectedLink">
</typeahead>

LocalStorage in Vue App with multiple inputs

i dont know if this is possible - but i am working on a Vue app with multiple input fields that posts to the same list - and i need this to be stored somehow, so when you refresh the site, the outputs from the input fields are saved.
This means both the taskList and subTaskList array should be saved ( i know i've only worked on taskList ).
The example i posted here saves the data fine, however if you refresh, it will post all the data in all the components, can this be fixed so it will only be in the right components?
const STORAGE_KEY = 'madplan-storage'
Vue.component('list-component', {
data: function() {
return {
newTask: "",
taskList: [],
newSubTask: "",
subTaskList: [],
};
},
created() {
this.taskList = JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]');
},
template:
'<div>' +
'<section class="prefetch">' +
'<input v-if="showInput" class="input typeahead" type="text" placeholder="Tilføj ret til madplanen" v-model="newTask" v-on:keyup.enter="addTask">' +
'</section>' +
'<details open v-for="task in taskList" v-bind:key="task.text" class="sub-list-item">' +
'<summary>{{ task.text }}<i class="fa fa-times" aria-hidden="true" v-on:click="removeTask(task)"></i>' + '</summary>' +
'<input class="subInput" type="text" placeholder="Tilføj til indøbsseddel" v-model="newSubTask" v-on:keyup.enter="addSubTask">' +
'</details>' +
'</div>',
computed: {
showInput: function() {
return !this.taskList.length
},
},
methods: {
//addTasks
//
addTask: function() {
var task = this.newTask.trim();
if (task) {
this.taskList.push({
text: task
});
this.newTask = "";
localStorage.setItem(STORAGE_KEY, JSON.stringify(this.taskList));
}
},
addSubTask: function() {
var task = this.newSubTask.trim();
if (task) {
this.subTaskList.push({
text: task
});
this.newSubTask = "";
this.$emit('addedtask', task);
localStorage.setItem(STORAGE_KEY, JSON.stringify(this.subTaskList));
}
},
//removeTasks
//
removeTask: function(task) {
var index = this.taskList.indexOf(task);
this.taskList.splice(index, 1);
},
},
});
new Vue({
el: "#madplan",
data: {
newTask: "",
taskList: [],
newSubTask: "",
subTaskList: [],
},
methods: {
acknowledgeAddedTask: function(cls, task) {
this.$data.subTaskList.push({
text: task,
class: "list-item " + cls
})
},
acknowledgeRemovedTask: function(task) {
this.$data.subTaskList = this.$data.subTaskList.filter(it => it.text != task.text)
},
removeSubTask: function(task) {
var index = this.subTaskList.indexOf(task);
this.subTaskList.splice(index, 1);
},
}
});
<section id="madplan" class="section-wrapper">
<section class="check-list">
<div id="mandag" class="dayWrapper">
<h1>Day One</h1>
<list-component
class="mandag"
v-on:addedtask='task => acknowledgeAddedTask("mandag", task)'
></list-component>
</div>
<div id="tirsdag" class="dayWrapper">
<h1>Day Two</h1>
<list-component
class="tirsdag"
v-on:addedtask='task => acknowledgeAddedTask("tirsdag", task)'
></list-component>
</div>
<ul id="indkobsseddel">
<h2>Shopping List</h2>
<li v-for="task in subTaskList" v-bind:key="task.text" :class="task.class">{{ task.text }}<i class="fa fa-times" aria-hidden="true" v-on:click="removeSubTask(task)"></i></li>
</ul>
</section>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://unpkg.com/vue/dist/vue.js" charset="utf-8"></script>
To be clear, i will come with an example:
As it is now, if i post "Foo" and "Bar" to the "Day One" component and refresh the page, it will then post "Foo" and "Bar" to both "Day One" and "Day Two".
Essentially, i would like to be able to post for an example "Foo" to "Day One", "Bar" to "Day Two" and from there post "Hello World" to the Shopping List, and it would all be saved in the right places, instead of posting everything everywhere.
BTW: I'm a scrub at backend work.
To persist global state, you may use the plugin vue-persistent-state like this:
import persistentStorage from 'vue-persistent-storage';
const initialState = {
newTask: "",
taskList: [],
newSubTask: "",
subTaskList: [],
};
Vue.use(persistentStorage, initialState);
Now newTask, taskList, newSubTask and subTaskList is available as data in all components and Vue instances. Any changes will be stored in localStorage, and you can use this.taskList etc. as you would in a vanilla Vue app.
Your list component now becomes:
Vue.component('list-component', {
// data removed
// created removed
template:
'<div>' +
'<section class="prefetch">' +
'<input v-if="showInput" class="input typeahead" type="text" placeholder="Tilføj ret til madplanen" v-model="newTask" v-on:keyup.enter="addTask">' +
'</section>' +
'<details open v-for="task in taskList" v-bind:key="task.text" class="sub-list-item">' +
'<summary>{{ task.text }}<i class="fa fa-times" aria-hidden="true" v-on:click="removeTask(task)"></i>' + '</summary>' +
'<input class="subInput" type="text" placeholder="Tilføj til indøbsseddel" v-model="newSubTask" v-on:keyup.enter="addSubTask">' +
'</details>' +
'</div>',
computed: {
showInput: function() {
return !this.taskList.length
},
},
methods: {
//addTasks
//
addTask: function() {
var task = this.newTask.trim();
if (task) {
this.taskList.push({
text: task
});
this.newTask = "";
// localStorage.setItem not needed
}
},
addSubTask: function() {
var task = this.newSubTask.trim();
if (task) {
this.subTaskList.push({
text: task
});
this.newSubTask = "";
// $emit not needed, state is global and shared
// localStorage.setItem not needed
}
},
//removeTasks
//
removeTask: function(task) {
var index = this.taskList.indexOf(task);
this.taskList.splice(index, 1);
},
},
});
If you want to understand how this works, the code is pretty simple. It basically
adds a mixin to make initialState available in all Vue instances, and
watches for changes and stores them.
Disclaimer: I'm the author of vue-persistent-state.