I am trying to pass an array that inside an object from a parent component to a child component but answers is coming up undefined. When checking the prop in the parent component the data is there, but when it gets past to the child it is undefined.
Vue.component('single-question', {
props: ['question'],
data: function () {
let vm = this
return {
answers: vm.question.answers
}
},
template: `<div class="question mb-3">
<div class="card">
<div class="card-body">
<h5 class="class-title">{{question.questionId}}</h5>
<p class="card-text">{{question.questionText}}</p>
<a class="btn btn-primary" data-toggle="collapse" v-bind:href="'#answerArea' + question.questionId" role="button" aria-expanded="false" aria-controls="answerArea">List answers</a>
</div>
</div>
<answer-area v-bind:id="'answerArea' + question.questionId" v-bind:answers="question.answers"></answer-area>
</div>`
})
Vue.component('answer-area', {
data: function() {
return {
show: false
}
},
props: ['answers'],
template: `<div class="collapse" id="">
<div class="card card-body">
<ol>
<li v-for="answer in answers" v-bind:key="answer.answerId"></li>
</ol>
</div>
</div>`
})
edit: Here is where the parent is declared
<div id="question-area">
<single-question v-for="question in questions" v-bind:key="question.questionId" v-bind:question="question"
v-bind:id="question.questionId"></single-question>
</div>
Parent data:
new Vue ({
el: '#question-area',
data: {
questions: [{
"answers": [{
"answerId": 21,
"questionId": 1,
"answerText": "One",
"iscorrect": false
},
{
"answerId": 40,
"questionId": 1,
"answerText": "In",
"iscorrect": false
}],
"questionId": 1,
"classCode": "123",
"questionText": "Result",
}],
},
})
Query:
$.getJSON(prestring + "/api/v1/classes/"+parsed.classcode+"/questions", function(json) {
vm.questions = json
vm.questions.forEach(question => {
$.ajax({
url: prestring + "/api/v1/questions/" + question.questionId + "/answers",
dataType: 'json',
//async: false,
success: function (json) {
question["answers"] = json
// question["answers"].push(json)
}
})
})
})
We would have to check what's in your data to be sure, but you are probably facing one of the Change Detection Caveats.
Try using Vue.set() to create your answers property, as below:
$.getJSON(prestring + "/api/v1/classes/"+parsed.classcode+"/questions",
function(json) {
vm.questions = json
vm.questions.forEach(question => {
$.ajax({
url: prestring + "/api/v1/questions/" + question.questionId + "/answers",
dataType: 'json',
//async: false,
success: function (json) {
// question["answers"] = json
Vue.set(question, 'answers', json); // changed this line
// question["answers"].push(json)
}
})
})
})
Related
HelloWorld.vue
<template>
<div>
<div v-for="box in boxes" :key="box.sname">
<BaseAccordian>
<template v-slot:title>{{ box.sname }}</template>
<template v-slot:content>
<div v-for="paint in paints" :key="paint.tname" class="line">
<List :content="matchingdata" :sname="box.sname" />
</div>
</template>
</BaseAccordian>
</div>
</div>
</template>
<script>
import BaseAccordian from "./BaseAccordian.vue";
import List from "./List.vue";
export default {
name: "HelloWorld",
components: {
BaseAccordian,
List,
},
data() {
return {
boxes: [
{
sname: "apple",
},
{
sname: "bananna",
},
{
sname: "grapes",
},
{
sname: "choc",
},
],
paints: [
{
tname: "a",
},
{
tname: "b",
},
{
tname: "c",
},
{
tname: "d",
},
{
tname: "e",
},
],
matchingdata: [
{
matchid: "1",
OverallStatus: "ok",
sname: "choc",
},
{
matchid: "2",
OverallStatus: "notok",
sname: "grapes",
},
],
};
},
};
</script>
BaseAccordion.vue
<template>
<div class="wrapper">
<div class="accordion">
<input type="checkbox" #click="toggleItem" />
<h2 class="title">
<slot name="title"></slot>
</h2>
</div>
<div v-show="show" class="content">
<slot name="content"></slot>
</div>
</div>
</template>
<script>
export default {
components: {},
data: function () {
return {
show: false,
};
},
methods: {
toggleItem: function () {
this.show = !this.show;
},
},
};
</script>
List.vue
<template>
<div class="">
<div
v-for="match in matchingData"
:key="match.matchid"
:class="{
green: match.OverallStatus === 'ok',
red: match.OverallStatus === 'notok',
}"
>
{{ match.OverallStatus }}
</div>
</div>
</template>
<script>
export default {
components: {},
props: {
content: {
type: Array,
required: true,
},
sname: {
type: String,
required: true,
},
},
data: function () {
return {};
},
methods: {},
computed: {
matchingData() {
return this.content.filter((a) => {
if (a.sname === this.sname) {
return true;
} else {
return false;
}
});
},
},
};
</script>
<style scoped>
</style>
I three arrays called matchingdata,boxes,paints array based on this three arrays, i am trying to filter the array.(nested v-for)
Now, I want to iterate the matchingdata array by comparing it with sname in boxes array. and Common value between matchingdata and boxes array is ""sname""
I tried above logic, and struck with computed property.
Expected Output:-
In List.vue component , i have
{{ match.OverallStatus }} where that field , i want to show,(from the matchingdata array) when user clicked on checkbox.
Taking the ""sname"" the common value from the matchingdata array and the boxes array
code:- https://codesandbox.io/s/damp-pine-27s2kn?file=/src/components/List.vue
As you're passing the sname property as a string via a prop to your List.vue component, you'll just need to use that string in your filter function.
matchingData() {
return this.content.filter((a) => a.sname === this.sname)
},
I've tried this in your codesandbox link and it is giving some output - but I'm not clear enough on what you're trying to achieve to know if this is the intended outcome.
Just incase you're not aware the 'filter' function returns a new array. It's not going to return a 'true/false' which I feel you may be trying to do.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
I have a basic table with an id column and a location name column. I also have an html form where a user can insert a new location into the table. Before inserting I want to check if my locations table already includes a location name and if it does exist I want to alert the user. If not it will be inserted into the table. First I query the locations table and then I try to use an if statement to see if the input value already matches a location name in my table. But I can't get it to work. My insert code works fine on it's own but I just can't get the conditions working. Any help would be greatly appreciated.
// add a new location
$("#btn-locationAdd").on("click", function() {
var addLocationName = $("#addLocationName");
$.ajax({
url: 'libs/php/getAllLocations.php',
method: 'POST',
dataType: 'json',
success: function (result) {
for (let i = 0; i < result.data.length; i++) {
if (result.data[i].name === addLocationName.val()) {
alert('This location aready exists')
} else {
$.ajax({
url: 'libs/php/insertLocation.php',
method: 'POST',
dataType: 'json',
data: {
addLocationName: addLocationName.val(),
},
success: function (result) {
$("#addNewLocationModal").modal('hide');
const newLocation = $("#alertTxt").html('New Location Record Created');
alertModal(newLocation);
}
});
}
this is the array I get after I query the locations table and get all locations in the table:
{
"status": {
"code": "200",
"name": "ok",
"description": "success",
"returnedIn": "1.5790462493896E-6 ms"
},
"data": [
{
"id": "1",
"name": "London"
},
{
"id": "2",
"name": "New York"
},
{
"id": "3",
"name": "Paris"
},
{
"id": "4",
"name": "Munich"
},
{
"id": "5",
"name": "Rome"
}
]
}
my html:
<!-- Add Location Modal -->
<div id="addNewLocationModal" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h2 class="modal-title">Add New Location</h2>
</div>
<div class="modal-body">
<input type="text" class="form-control" placeholder="Location Name" id="addLocationName"><br>
</div>
<div class="modal-footer">
<input type="button" id="btn-locationAdd" value="Add Location" class="btn btn-success">
<input type="button" id="btn-addLocationCancel" value="CANCEL" data-bs-dismiss="modal" class="btn btn-secondary">
</div>
</div>
</div>
</div>
$("#btn-locationAdd").on("click", function () {
var addLocationName = $("#addLocationName");
$.ajax({
url: 'libs/php/getAllLocations.php',
method: 'POST',
dataType: 'json',
success: function (result) {
let existed = false;
for (let i = 0; i < result.data.length; i++) {
if (result.data[i].name === addLocationName.val()) {
existed = true
break
}
}
if(existed){
alert('This location aready exists')
return
}
$.ajax({
url: 'libs/php/insertLocation.php',
method: 'POST',
dataType: 'json',
data: {
addLocationName: addLocationName.val(),
},
success: function (result) {
$("#addNewLocationModal").modal('hide');
const newLocation = $("#alertTxt").html('New Location Record Created');
alertModal(newLocation);
}
});
}
})
})
I have a problem with binding checkboxes using Vuex. On checkbox I use v-model with variable which has getter and setter to set or get value in store, the problem is that I get wrong data in store and I don't understand what cause the problem. Checkboxes bind to store property and this property must contain array of id's from checkboxes, but when I click checkbox more than one time it rewrite or remove store values. Can anyone help me to understand why does this happens? Link to jsFiddle.
The code
const store = new Vuex.Store({
state: {
checkboxes: {},
checked: {}
},
mutations: {
setCheckboxes(state, dataObj){
console.log(dataObj);
state.checkboxes = dataObj.data;
let firstElem = dataObj.data[Object.keys(dataObj.data)[0]];
state.checked[firstElem.parent_id] = [firstElem.id];
console.log(state.checked);
},
setTreeState(state, dataObj){
state.checked[dataObj.id] = dataObj.value;
console.log(state.checked);
}
}
});
Vue.component('checkboxTree', {
template: "#checkboxTree",
});
Vue.component('checkboxToggle', {
template: "#checkboxToggle",
data(){
return {
store
}
},
computed: {
value:{
get(){
return store.state.checked[this.checkbox.parent_id];
},
set(val){
store.commit({
type: 'setTreeState',
id: this.checkbox.parent_id,
value: val
});
},
},
},
props: ['checkbox']
});
const app = new Vue({
el: "#app",
store,
data: {
checkboxData: {
...
},
},
mounted(){
this.$store.commit({
type: 'setCheckboxes',
data: this.checkboxData
});
}
})
Template
<div id="app">
<checkbox-tree :checkboxData="checkboxData"></checkbox-tree>
</div>
<template id="checkboxTree">
<div>
<p>checkbox tree</p>
<form>
<ul>
<li v-for="checkbox in $store.state.checkboxes">
<checkbox-toggle :checkbox="checkbox"></checkbox-toggle>
</li>
</ul>
</form>
</div>
</template>
<template id="checkboxToggle">
<div>
<label>{{ checkbox.id }}</label>
<input type="checkbox"
:value="checkbox.id"
:id="'checkbox-' + checkbox.id"
:name="'checkbox-' + checkbox.id"
v-model="value"
>
</div>
</template>
Okay, assuming you want checked to contain ids of selected objects, I had to restructure your code significantly:
const removeFromArray = (array, value) => {
const newArray = [...array];
const index = newArray.indexOf(value);
if (index > -1) {
newArray.splice(index, 1);
return newArray;
}
return array;
}
const store = new Vuex.Store({
state: {
checkboxes: {},
checked: [],
},
mutations: {
addToChecked(state, id) {
state.checked.push(id);
},
removeFromChecked(state, id) {
const newArray = removeFromArray(state.checked, id);
state.checked = newArray;
},
setCheckboxes(state, data) {
state.checkboxes = data;
},
}
});
Vue.component('checkboxTree', {
template: "#checkboxTree",
computed: {
checkboxes() {
return this.$store.state.checkboxes;
},
},
});
Vue.component('checkboxToggle', {
template: "#checkboxToggle",
computed: {
value:{
get(){
return this.$store.state.checked.indexOf(this.checkbox.id) > -1;
},
set(val){
const mutation = val ? 'addToChecked' : 'removeFromChecked';
this.$store.commit(mutation, this.checkbox.id);
},
},
},
props: ['checkbox'],
});
const app = new Vue({
el: "#app",
store,
data: {
checkboxData: {
"5479": {
"id": 5479,
"title": "Место оказания услуг",
"type": "checkbox",
"dependencies": "",
"description": "",
"parent_id": 5478,
"npas": ""
},
"5480": {
"id": 5480,
"title": "Способы оказания услуг",
"type": "checkbox",
"dependencies": "",
"description": "",
"parent_id": 5478,
"npas": "50"
},
"5481": {
"id": 5481,
"title": "Объем и порядок содействия Заказчика в оказании услуг",
"type": "checkbox",
"dependencies": "",
"description": "",
"parent_id": 5478,
"npas": "54"
},
}
},
computed: {
stateRaw() {
return JSON.stringify(this.$store.state, null, 2);
},
},
mounted() {
this.$store.commit('setCheckboxes', this.checkboxData);
const firstElementKey = Object.keys(this.checkboxData)[0];
const firstElement = this.checkboxData[firstElementKey];
this.$store.commit('addToChecked', firstElement.id);
}
})
<script src="https://unpkg.com/vue"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/3.0.1/vuex.js"></script>
<div id="app">
<checkbox-tree :checkboxData="checkboxData"></checkbox-tree>
<pre v-text="stateRaw"></pre>
</div>
<template id="checkboxTree">
<div>
<p>checkbox tree</p>
<form>
<ul>
<li v-for="checkbox in checkboxes">
<checkbox-toggle :checkbox="checkbox"></checkbox-toggle>
</li>
</ul>
</form>
</div>
</template>
<template id="checkboxToggle">
<div>
<label>{{ checkbox.id }}</label>
<input
type="checkbox"
:value="checkbox.id"
:id="'checkbox-' + checkbox.id"
:name="'checkbox-' + checkbox.id"
v-model="value">
{{value}}
</div>
</template>
Using this code as an example, you can populate checked however you want to.
Also, a jsfiddle link for you: https://jsfiddle.net/oniondomes/ckj7mgny/
My JSON is:
[{
"name": "Health care",
"cat_id": 1
}, {
"name": "Education",
"cat_id": 2
}, {
"name": "Bakery",
"cat_id": 3
}, {
"name": "Software company",
"cat_id": 4
}]
My vue js script is.
<script>
new Vue({
el: '#categories' ,
data: {
articles: [],
},
mounted() {
this.$nextTick(function() {
var self = this;
$.ajax({
url: "https://",
method: "GET",
dataType: "JSON",
success: function (e) {
self.articles = e.articles;
console.log(e.articles)
},
});
})
},
})
</script>
The html code used is
<div v-for="post in articles" id="categories">
<div class="top">
<h4>Top Categories</h4>
<ul class="mov_list">
<li><i class="fa fa-star"></i></li>
<li>77</li>
<li>{{post.name}}</li>
</ul>
</div>
</div>
This is where I am trying to display the different categories. But I am getting some errors. Can anybody please help me to display the same. I am weak in js
It looks like a scope issue. self has to be declared outside of the function. Still I believe you do not need to specify the callback. Something like this should be sufficient:
<script>
new Vue({
el: '#app',
data: {
articles: [],
},
mounted() {
var self = this;
$.ajax({
url: "https://n2s.herokuapp.com/api/post/get_all_category/",
method: "GET",
dataType: "JSON",
success: function(e) {
self.articles = e.articles;
console.log(e.articles)
},
});
},
})
</script>
html:
<div id="app">
<div v-for="post in articles">
<div class="top">
<h4>Top Categories</h4>
<ul class="mov_list">
<li><i class="fa fa-star"></i></li>
<li>77</li>
<li>{{post.name}}</li>
</ul>
</div>
</div>
</div>
Cheers!
I've made a datatable and was able to add the edit and delete links to each row of the table. The links however do not seem to do anything. I am trying to redirect to an edit page upon click, but I am having trouble obtaining thethe id of the record that is in my model of the row that I'm wanting to edit to add to the url. Here is my markup/script that makes the table within a modal.
#model ReconciliationApp.Models.IReconciliationForm
<div class="img-responsive center-block" id="formButtons">
<div>
<div class="btn-group row col-sm-12">
#Html.ActionLink("Top", "Top", null, new { #class = "btn btn-primary" })
#try
{
#Html.ActionLink("Previous", "Previous", null, new { id = Model.Id }, new { #class = "btn btn-primary" })
#Html.ActionLink("Next", "Next", null, new { id = Model.Id }, new { #class = "btn btn-primary" })
#Html.ActionLink("Bottom", "Bottom", null, new { #class = "btn btn-primary" })
}
catch (NullReferenceException)
{
#Html.ActionLink("Previous", "Previous", null, null, new { #class = "btn btn-primary" })
#Html.ActionLink("Next", "Next", null, null, new { #class = "btn btn-primary" })
#Html.ActionLink("Bottom", "Bottom", null, new { #class = "btn btn-primary" })
}
<button type="button" class="btn btn-primary" data-toggle="modal" data-target=".browse-modal-lg">Browse</button>
</div>
</div>
</div>
<div class="modal fade browse-modal-lg" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title">Browse Members</h4>
</div>
<div class="container-fluid" style="padding-left: 50px;">
<div class="row">
<div class="col-md-12">
<div class="panel panel-primary list-panel" id="list-panel">
<div class="panel-heading list-panel-heading">
<h3 class="panel-title list-panel-title">Products</h3>
<button type="button" class="btn btn-default btn-md refresh-button" id="refresh-button">
<span class="glyphicon glyphicon-refresh" aria-hidden="true"></span> Refresh
</button>
</div>
<div class="panel-body">
<table id="data-table" class="table table-striped table-bordered" style="width:100%"></table>
</div>
</div>
</div>
</div>
<script type="text/javascript">
$(function () {
var controller = "#ViewData["controller"]";
var productListVM = {
dt: null,
init: function () {
dt = $('#data-table').DataTable({
"serverSide": true,
"processing": true,
"ajax": "/" + controller + "/DataTableGet",
"columns": [
{ "title": "MemberID", "data": "MemberID", "searchable": false },
{ "title": "BrandID", "data": "BrandID" },
{ "title": "FirstName", "data": "FirstName" },
{ "title": "LastName", "data": "LastName" },
{ "title": "WhenCreated", "data": "WhenCreated" },
{ "title": "ProcessedBy", "data": "ProcessedBy" },
{
data: null,
className: "center",
defaultContent: `Edit / Delete`
},
],
"lengthMenu": [[5, 10, 25, 50], [5, 10, 25, 50]],
});
},
refresh: function () {
dt.ajax.reload();
}
}
// Edit record
$('#example').on('click', 'a.editor_edit', function (e) {
e.preventDefault();
editor
.title('Edit record')
.buttons({ "label": "Update", "fn": function () { editor.submit() } })
.edit($(this).closest('tr'));
});
// Delete a record
$('#example').on('click', 'a.editor_remove', function (e) {
e.preventDefault();
editor
.title('Edit record')
.message("Are you sure you wish to delete this row?")
.buttons({ "label": "Delete", "fn": function () { editor.submit() } })
.remove($(this).closest('tr'));
});
$('#refresh-button').on("click", productListVM.refresh);
productListVM.init();
})
</script>
</div>
</div>
</div>
</div>
As you can see in
`defaultContent: `Edit / Delete``
I'm successfully able to add the controller (dynamically) into the url to direct to, but the url needs a particular record, or id to edit/delete, but I can't seem to find a way to be able to get the current row that the link is on. Is this possible at all? With a bunch of research here are some of the things I've tried so far, but to no avail.
I've made the rowIndex variable and passed it into the url similar to the controller
var rowIndex = $(this).closest('tr').prevAll().length;
I've made the table variable and then passed the second part as the last parameter in the url.
var table = $('#table-data').DataTable(); ${table.row(this).index()}
The above are workarounds, but I would prefer to get the Id (which is part of my model) of the row that the link is on. I've tried referencing the model directly like Model.Id, but that doesn't seem to be working at all.
Any help or direction would be greatly appreciated, as I'm somewhat new to javascript/jquery. Thanks!
Basically after looking at the datatables documentation for the umpteenth time I ended up taking out the default content and replaced it with render and called a function which returned the data I needed. Then passed it as a variable into the url. Here is my changed script.
<script type="text/javascript">
$(function () {
var controller = "#ViewData["controller"]";
var productListVM = {
dt: null,
init: function (oObj) {
dt = $('#data-table').DataTable({
"serverSide": true,
"processing": true,
"ajax": "/" + controller + "/DataTableGet",
"columns": [
{ "title": "MemberID", "data": "MemberID", "searchable": false },
{ "title": "BrandID", "data": "BrandID" },
{ "title": "FirstName", "data": "FirstName" },
{ "title": "LastName", "data": "LastName" },
{ "title": "WhenCreated", "data": "WhenCreated" },
{ "title": "ProcessedBy", "data": "ProcessedBy" },
{
data: null,
className: "center",
//re: `Edit / Delete`,
"render": function (data, type, full, meta) {
return 'Edit / Delete';
}
},
],
"lengthMenu": [[5, 10, 25, 50], [5, 10, 25, 50]],
});
},
refresh: function () {
dt.ajax.reload();
}
}
// Edit record
$('#example').on('click', 'a.editor_edit', function (e) {
e.preventDefault();
editor
.title('Edit record')
.buttons({ "label": "Update", "fn": function () { editor.submit() } })
.edit($(this).closest('tr'));
});
// Delete a record
$('#example').on('click', 'a.editor_remove', function (e) {
e.preventDefault();
editor
.title('Edit record')
.message("Are you sure you wish to delete this row?")
.buttons({ "label": "Delete", "fn": function () { editor.submit() } })
.remove($(this).closest('tr'));
});
$('#refresh-button').on("click", productListVM.refresh);
productListVM.init();
})
</script>