How to get parent key from child in Object - javascript

Given an Object, I want to get the parent key starting from the child. Since I only care about the key I'm iterating from enntries, but it always returns undefined.
var book = {
"chapter1": {
"paragraph1": {
"text": "..."
},
"paragraph2": {
"text": "..."
}
},
"chapter2": {
"paragraph3": {
"text": "..."
},
"paragraph4": {
"text": "..."
}
},
"chapter3": {
"paragraph5": {
"text": "..."
},
"paragraph6": {
"text": "..."
}
}
};
var section = "paragraph3";
const category = Object.entries(book).find(([, e]) => Object.values(e).includes(section)); /// should return chapter2
if (category) {
console.log(category[0], category[1]);
} else {
console.log("Not Found");
}

Simply replace .values() by .keys() in your code:
var book = {
"chapter1": {
"paragraph1": {
"text": "..."
},
"paragraph2": {
"text": "..."
}
},
"chapter2": {
"paragraph3": {
"text": "..."
},
"paragraph4": {
"text": "..."
}
},
"chapter3": {
"paragraph5": {
"text": "..."
},
"paragraph6": {
"text": "..."
}
}
};
var section = "paragraph3";
const category = Object.entries(book).find(([, e]) => Object.keys(e).includes(section)); /// should return chapter2
if (category) {
console.log(category[0], category[1]);
} else {
console.log("Not Found");
}

here is a solution how to get parent key from children
var book = {
chapter1: {
paragraph1: {
text: '...'
},
paragraph2: {
text: '...'
}
},
chapter2: {
paragraph3: {
text: '...'
},
paragraph4: {
text: '...'
}
},
chapter3: {
paragraph5: {
text: '...'
},
paragraph6: {
text: '...'
}
}
};
var section = 'paragraph3';
const category = Object.entries(book).find(e =>
Object.keys(e[1]).includes(section)
); /// should return chapter2
if (category) {
console.log(category[0]);
} else {
console.log('Not Found');
}

Related

JS/ES6: Undefined check on destructuring on a dynamic defined variable

I'm using some destructuring like this based on dynamic data:
const {
groupSku,
parentGroupSKU,
orderOriginationId,
sku,
quantity,
partialShip,
categoryID,
masterCategoryID,
siteId,
assortmentId,
servicing,
servicing: { itemServiceTypeID },
servicing: { style },
servicing: { text },
servicing: { serviceQuantity }
} = item;
The following can be undefined -
servicing, servicing: { itemServiceTypeID }, servicing: { style }, servicing: { text }, servicing: { serviceQuantity }
How do check the above undefined when assigned to const ?
I wanted to check if "servicing" is undefined then rest of under servicing should omitted.
Was getting y.servicing is undefined in the console in were an item not having servicing.
Try this:
let item = {
masterCategoryID: '<masterCategoryID>',
assortmentId: '<assortmentId>',
siteId: '<siteId>',
someDefinedProp: {
someDefinedPropChild: '<someDefinedPropChild>'
}
}
const {
masterCategoryID,
siteId,
assortmentId,
someDefinedProp,
someDefinedProp: { someDefinedPropChild } = {},
someDefinedProp: { someUndefinedPropChild } = {},
servicing,
servicing: { itemServiceTypeID } = {},
servicing: { style } = {},
servicing: { text } = {},
servicing: { serviceQuantity } = {}
} = item;
console.log('someDefinedProp:', someDefinedProp)
console.log('someDefinedPropChild:', someDefinedPropChild)
console.log('someUndefinedPropChild:', someUndefinedPropChild)
console.log('servicing:', servicing)
console.log('itemServiceTypeID:', itemServiceTypeID)
console.log('style:', style)
console.log('text:', text)
console.log('serviceQuantity:', serviceQuantity)

Uncaught SyntaxError: Unexpected end of JSON input at JSON.parse (<anonymous>)

I need some help with this error:
Uncaught SyntaxError: Unexpected end of JSON input
at JSON.parse ()
at Object.success (dashboard.js:22)
at fire (jquery-3.3.1.js:3268)
at Object.fireWith [as resolveWith] (jquery-3.3.1.js:3398)
at done (jquery-3.3.1.js:9305)
at XMLHttpRequest. (jquery-3.3.1.js:9548)
I try to transform a string to a json object using JSON.parse() that cause that error.
I am using oracleJet and this is my code:
function DashboardViewModel() {
var self = this;
self.lineTypeValue = ko.observable('curved');
var scatterSeries = [];
$.getJSON( "http://localhost:8080/points", function (data) {
console.info(data);
var ch = '{"name":"graphe1","items":'+JSON.stringify(data.results[1])+ '}';
console.info(ch);
console.info(JSON.parse(scatterSeries));
scatterSeries.push(JSON.parse(ch));
});
/* chart data */
this.scatterSeriesValue = ko.observableArray(scatterSeries);
self.lineTypeOptions = [
{id: 'straight', label: 'straight'},
{id: 'curved', label: 'curved'},
{id: 'stepped', label: 'stepped'},
{id: 'segmented', label: 'segmented'},
{id: 'none', label: 'none'}
];
}
The Json that I get from "http://localhost:8080/points" look like this:
{ "results":[
[
{
"b":"0.110547334",
"cost":"0.000000",
"w":"1.998889"
}
],
[
{
"x":0,
"y":0
},
{
"x":1,
"y":2
},
{
"x":2,
"y":4
},
{
"x":3,
"y":6
},
{
"x":4,
"y":8
},
{
"x":5,
"y":10
},
{
"x":6,
"y":12
},
{
"x":7,
"y":14
},
{
"x":8,
"y":16
},
{
"x":9,
"y":18
},
{
"x":10,
"y":20
},
{
"x":11,
"y":22
},
{
"x":12,
"y":24
},
{
"x":13,
"y":26
},
{
"x":14,
"y":28
},
{
"x":15,
"y":30
},
{
"x":16,
"y":32
},
{
"x":17,
"y":34
},
{
"x":18,
"y":36
},
{
"x":19,
"y":38
},
{
"x":20,
"y":40
},
{
"x":21,
"y":42
},
{
"x":22,
"y":44
},
{
"x":23,
"y":46
},
{
"x":24,
"y":48
},
{
"x":25,
"y":50
},
{
"x":26,
"y":52
},
{
"x":27,
"y":54
},
{
"x":28,
"y":56
},
{
"x":29,
"y":58
},
{
"x":30,
"y":60
},
{
"x":31,
"y":62
},
{
"x":32,
"y":64
},
{
"x":33,
"y":66
},
{
"x":34,
"y":68
},
{
"x":35,
"y":70
},
{
"x":36,
"y":72
},
{
"x":37,
"y":74
},
{
"x":38,
"y":76
},
{
"x":39,
"y":78
},
{
"x":40,
"y":80
},
{
"x":41,
"y":82
},
{
"x":42,
"y":84
},
{
"x":43,
"y":86
},
{
"x":44,
"y":88
},
{
"x":45,
"y":90
},
{
"x":46,
"y":92
},
{
"x":47,
"y":94
},
{
"x":48,
"y":96
},
{
"x":49,
"y":98
},
{
"x":50,
"y":100
},
{
"x":51,
"y":102
},
{
"x":52,
"y":104
},
{
"x":53,
"y":106
},
{
"x":54,
"y":108
},
{
"x":55,
"y":110
},
{
"x":56,
"y":112
},
{
"x":57,
"y":114
},
{
"x":58,
"y":116
},
{
"x":59,
"y":118
},
{
"x":60,
"y":120
},
{
"x":61,
"y":122
},
{
"x":62,
"y":124
},
{
"x":63,
"y":126
},
{
"x":64,
"y":128
},
{
"x":65,
"y":130
},
{
"x":66,
"y":132
},
{
"x":67,
"y":134
},
{
"x":68,
"y":136
},
{
"x":69,
"y":138
},
{
"x":70,
"y":140
},
{
"x":71,
"y":142
},
{
"x":72,
"y":144
},
{
"x":73,
"y":146
},
{
"x":74,
"y":148
},
{
"x":75,
"y":150
},
{
"x":76,
"y":152
},
{
"x":77,
"y":154
},
{
"x":78,
"y":156
},
{
"x":79,
"y":158
},
{
"x":80,
"y":160
},
{
"x":81,
"y":162
},
{
"x":82,
"y":164
},
{
"x":83,
"y":166
},
{
"x":84,
"y":168
},
{
"x":85,
"y":170
},
{
"x":86,
"y":172
},
{
"x":87,
"y":174
},
{
"x":88,
"y":176
},
{
"x":89,
"y":178
},
{
"x":90,
"y":180
},
{
"x":91,
"y":182
},
{
"x":92,
"y":184
},
{
"x":93,
"y":186
},
{
"x":94,
"y":188
},
{
"x":95,
"y":190
},
{
"x":96,
"y":192
},
{
"x":97,
"y":194
},
{
"x":98,
"y":196
},
{
"x":99,
"y":198
}
]]}
and what I want the variable scatterSeries to hold is a table like this one:
[ {
name:"graphe1",
items:[
{
x:8,
y:2
},
{
x:15,
y:15
},
{
x:25,
y:26
},
{
x:33,
y:22
},
{
x:36,
y:40
}
]},]
what I get in the console about the string ch is this:
{"name":"graphe1","items":[{"x":0,"y":0},{"x":1,"y":2},{"x":2,"y":4},{"x":3,"y":6},{"x":4,"y":8},{"x":5,"y":10},{"x":6,"y":12},{"x":7,"y":14},{"x":8,"y":16},{"x":9,"y":18},{"x":10,"y":20},{"x":11,"y":22},{"x":12,"y":24},{"x":13,"y":26},{"x":14,"y":28},{"x":15,"y":30},{"x":16,"y":32},{"x":17,"y":34},{"x":18,"y":36},{"x":19,"y":38},{"x":20,"y":40},{"x":21,"y":42},{"x":22,"y":44},{"x":23,"y":46},{"x":24,"y":48},{"x":25,"y":50},{"x":26,"y":52},{"x":27,"y":54},{"x":28,"y":56},{"x":29,"y":58},{"x":30,"y":60},{"x":31,"y":62},{"x":32,"y":64},{"x":33,"y":66},{"x":34,"y":68},{"x":35,"y":70},{"x":36,"y":72},{"x":37,"y":74},{"x":38,"y":76},{"x":39,"y":78},{"x":40,"y":80},{"x":41,"y":82},{"x":42,"y":84},{"x":43,"y":86},{"x":44,"y":88},{"x":45,"y":90},{"x":46,"y":92},{"x":47,"y":94},{"x":48,"y":96},{"x":49,"y":98},{"x":50,"y":100},{"x":51,"y":102},{"x":52,"y":104},{"x":53,"y":106},{"x":54,"y":108},{"x":55,"y":110},{"x":56,"y":112},{"x":57,"y":114},{"x":58,"y":116},{"x":59,"y":118},{"x":60,"y":120},{"x":61,"y":122},{"x":62,"y":124},{"x":63,"y":126},{"x":64,"y":128},{"x":65,"y":130},{"x":66,"y":132},{"x":67,"y":134},{"x":68,"y":136},{"x":69,"y":138},{"x":70,"y":140},{"x":71,"y":142},{"x":72,"y":144},{"x":73,"y":146},{"x":74,"y":148},{"x":75,"y":150},{"x":76,"y":152},{"x":77,"y":154},{"x":78,"y":156},{"x":79,"y":158},{"x":80,"y":160},{"x":81,"y":162},{"x":82,"y":164},{"x":83,"y":166},{"x":84,"y":168},{"x":85,"y":170},{"x":86,"y":172},{"x":87,"y":174},{"x":88,"y":176},{"x":89,"y":178},{"x":90,"y":180},{"x":91,"y":182},{"x":92,"y":184},{"x":93,"y":186},{"x":94,"y":188},{"x":95,"y":190},{"x":96,"y":192},{"x":97,"y":194},{"x":98,"y":196},{"x":99,"y":198}]}
Any help please?!! :( :(
You are calling:
JSON.parse(scatterSeries)
But when you defined scatterSeries, you said:
var scatterSeries = [];
When you try to parse it as JSON it is converted to a string (""), which is empty, so you reach the end of the string before having any of the possible content of a JSON text.
scatterSeries is not JSON. Do not try to parse it as JSON.
data is not JSON either (getJSON will parse it as JSON automatically).
ch is JSON … but shouldn't be. You should just create a plain object in the first place:
var ch = {
"name": "graphe1",
"items": data.results[1]
};
scatterSeries.push(ch);
In short, for what you are doing, you shouldn't have JSON.parse anywhere in your code. The only place it should be is in the jQuery library itself.
I was trying to debug this same error (I was writing code in TypeScript), but no matter what I did, the error didn't go away, it was really persistent.
I tried to look into the solution in many blogs and also this SO thread. I tried everything and nothing worked out.
Finally, I saw that I created the required file named products.json in which I gave a single extra newline (meaning, previously the file had 1 empty line, now it had 2 empty lines) and was following good GitHub practices as mentioned here.
Because of that single extra newline in my products.json file, I wasted 2 hours fixing a bug that didn't exist in the first place.
Finally when I deleted the entire products.json file and re-ran the entire thing, I didn't get any runtime errors and everything was running without any problems.
What I learned by going through all this?
It's that experience is the teacher of all things.
Remove this line from your code:
console.info(JSON.parse(scatterSeries));
Issue is with the Json.parse of empty array - scatterSeries , as you doing console log of scatterSeries before pushing ch
var data = { "results":[
[
{
"b":"0.110547334",
"cost":"0.000000",
"w":"1.998889"
}
],
[
{
"x":0,
"y":0
},
{
"x":1,
"y":2
},
{
"x":2,
"y":4
},
{
"x":3,
"y":6
},
{
"x":4,
"y":8
},
{
"x":5,
"y":10
},
{
"x":6,
"y":12
},
{
"x":7,
"y":14
},
{
"x":8,
"y":16
},
{
"x":9,
"y":18
},
{
"x":10,
"y":20
},
{
"x":11,
"y":22
},
{
"x":12,
"y":24
},
{
"x":13,
"y":26
},
{
"x":14,
"y":28
},
{
"x":15,
"y":30
},
{
"x":16,
"y":32
},
{
"x":17,
"y":34
},
{
"x":18,
"y":36
},
{
"x":19,
"y":38
},
{
"x":20,
"y":40
},
{
"x":21,
"y":42
},
{
"x":22,
"y":44
},
{
"x":23,
"y":46
},
{
"x":24,
"y":48
},
{
"x":25,
"y":50
},
{
"x":26,
"y":52
},
{
"x":27,
"y":54
},
{
"x":28,
"y":56
},
{
"x":29,
"y":58
},
{
"x":30,
"y":60
},
{
"x":31,
"y":62
},
{
"x":32,
"y":64
},
{
"x":33,
"y":66
},
{
"x":34,
"y":68
},
{
"x":35,
"y":70
},
{
"x":36,
"y":72
},
{
"x":37,
"y":74
},
{
"x":38,
"y":76
},
{
"x":39,
"y":78
},
{
"x":40,
"y":80
},
{
"x":41,
"y":82
},
{
"x":42,
"y":84
},
{
"x":43,
"y":86
},
{
"x":44,
"y":88
},
{
"x":45,
"y":90
},
{
"x":46,
"y":92
},
{
"x":47,
"y":94
},
{
"x":48,
"y":96
},
{
"x":49,
"y":98
},
{
"x":50,
"y":100
},
{
"x":51,
"y":102
},
{
"x":52,
"y":104
},
{
"x":53,
"y":106
},
{
"x":54,
"y":108
},
{
"x":55,
"y":110
},
{
"x":56,
"y":112
},
{
"x":57,
"y":114
},
{
"x":58,
"y":116
},
{
"x":59,
"y":118
},
{
"x":60,
"y":120
},
{
"x":61,
"y":122
},
{
"x":62,
"y":124
},
{
"x":63,
"y":126
},
{
"x":64,
"y":128
},
{
"x":65,
"y":130
},
{
"x":66,
"y":132
},
{
"x":67,
"y":134
},
{
"x":68,
"y":136
},
{
"x":69,
"y":138
},
{
"x":70,
"y":140
},
{
"x":71,
"y":142
},
{
"x":72,
"y":144
},
{
"x":73,
"y":146
},
{
"x":74,
"y":148
},
{
"x":75,
"y":150
},
{
"x":76,
"y":152
},
{
"x":77,
"y":154
},
{
"x":78,
"y":156
},
{
"x":79,
"y":158
},
{
"x":80,
"y":160
},
{
"x":81,
"y":162
},
{
"x":82,
"y":164
},
{
"x":83,
"y":166
},
{
"x":84,
"y":168
},
{
"x":85,
"y":170
},
{
"x":86,
"y":172
},
{
"x":87,
"y":174
},
{
"x":88,
"y":176
},
{
"x":89,
"y":178
},
{
"x":90,
"y":180
},
{
"x":91,
"y":182
},
{
"x":92,
"y":184
},
{
"x":93,
"y":186
},
{
"x":94,
"y":188
},
{
"x":95,
"y":190
},
{
"x":96,
"y":192
},
{
"x":97,
"y":194
},
{
"x":98,
"y":196
},
{
"x":99,
"y":198
}
]]};
var scatterSeries = [];
var ch = '{"name":"graphe1","items":'+JSON.stringify(data.results[1])+ '}';
console.info(ch);
scatterSeries.push(JSON.parse(ch));
console.info(scatterSeries);
code sample - https://codepen.io/nagasai/pen/GGzZVB
You define var scatterSeries = [];, and then try to parse it as a json string at console.info(JSON.parse(scatterSeries)); which obviously fails. The variable is converted to an empty string, which causes an "unexpected end of input" error when trying to parse it.
Encountered this error in the following function when I tried to pull 'nothing' from LS
Quick fix for posterity
const getUserFromLocalStorage = () => {
try {
return JSON.parse(localStorage.getItem('user') || '');
} catch (error) {
return null;
}
};
In my case, using .NET 6, the problem was that the controller was declared as void and did not return any value.
Simply changing the method declaration to int and adding return 0; solved this issue for me.
[HttpPost]
public int MyMethod(string text)
{
_logger.Log(text);
return 0;
}
This is because of the data that you are trying to parse is not in a parsable format .
so i suggest to check the data is parsable or not before define the parse.
const IsParsable = (data) => {
try {
JSON.parse(data);
} catch (e) {
return false;
}
return true;
}
var Obj= JSON.stringify({
"name": "graphe1",
"items": data.results[1]
})
return IsParsable (Obj) ? JSON.parse(Obj) : false

Dialogue.Directive Not Working When emiting the handler ?

After A dialogue is completed and its confirmationStatus is changed to confirmed than i emit another dialogue directive ./ intent but its directive dosent work and it directly jumps to emit and ends
code :-
const handlers = {
'LaunchRequest': function () {
this.response.speak(welcomeOutput).listen(welcomeReprompt);
var userID = this.event.session.user.userID;
console.log(userID);
this.emit(':responseReady');
},
'createOrder': function () {
var filledSlots = delegateSlotCollection.call(this);
this.emit(':tell','Create Order Ended');
},
'addOrder': function () {
var filledSlots = delegateSlotCollectionSecond.call(this);
},
'AMAZON.HelpIntent': function () {
speechOutput = "";
reprompt = "";
this.response.speak(speechOutput).listen(reprompt);
this.emit(':responseReady');
},
'AMAZON.YesIntent': function () {
this.emit("Yes Triggered");
},
'AMAZON.NoIntent': function () {
this.emit("NO Triggered");
},
'AMAZON.CancelIntent': function () {
speechOutput = "Okay Your Request is Cancelled";
this.response.speak(speechOutput);
this.emit(':responseReady');
},
'AMAZON.StopIntent': function () {
speechOutput = "";
this.response.speak(speechOutput);
this.emit(':responseReady');
},
'SessionEndedRequest': function () {
var speechOutput = "";
this.response.speak(speechOutput);
this.emit(':responseReady');
},
'AMAZON.FallbackIntent': function () {
console.log('AMAZON FALL BACKINTENT');
},
'Unhandled': function () {
console.log("Unhandled");
},
};
exports.handler = (event, context) => {
var alexa = Alexa.handler(event, context);
alexa.appId = APP_ID;
// To enable string internationalization (i18n) features, set a resources object.
//alexa.resources = languageStrings;
alexa.registerHandlers(handlers);
alexa.execute();
};
// END of Intent Handlers {} ========================================================================================
// 3. Helper Function =================================================================================================
function delegateSlotCollection() {
console.log("in delegateSlotCollection");
console.log("current dialogState: " + this.event.request.dialogState);
if (this.event.request.dialogState === "STARTED") {
var updatedIntent = this.event.request.intent;
this.emit(":delegate", updatedIntent);
} else if (this.event.request.dialogState !== "COMPLETED") {
console.log("in not completed");
this.emit(":delegate")
} else {
if (this.event.request.intent.confirmationStatus === 'CONFIRMED'){
this.emit('addOrder');
}
return this.event.request.intent;
}
}
function delegateSlotCollectionSecond() {
console.log("in delegateSlotCollection");
console.log("current dialogState: " + this.event.request.dialogState);
if (this.event.request.dialogState === "STARTED") {
var updatedIntent = this.event.request.intent;
this.emit(":delegate", updatedIntent);
} else if (this.event.request.dialogState !== "COMPLETED") {
console.log("in not completed");
this.emit(":delegate")
} else {
if (this.event.request.intent.confirmationStatus === 'CONFIRMED'){
Console.log("Vegeta");
console.log(this.event.request.intent.confirmationStatus);
}
return this.event.request.intent;
}
}
This Is the code that i am using so when first createOrder Dialogue is completed it ask for confirmation and when i say yes than add order is emited but its dialogue directive didnt work it directly emits the statement so how to solve tghis problem ?
'createOrder': function () {
this.emit(':ask','tell me item name');
},
'productIntent': function(){
this.event.request.intent.slots.product.value //have an intent and slot for product
this.attributes['anyName'] = "product"; put product in session
this.emit(':ask','tell me quantity');
}
'quantityIntent': function(){
this.event.request.intent.slots.quantity.value //have an intent and slot for quality
this.attributes['anyName'] = "quantity"; put quantity in session
this.emit(':ask','do you want to add more item');
}
'Amazon.yesIntent': function () {
this.emit("createOrder"); //repeat
},
//handle no intent by retrieving all data and making your order
let retriveddata = this.attributes['anyName'];
You get the idea.
This way you won't lose the data between intents unless the session ends.
{
"interactionModel": {
"languageModel": {
"invocationName": "hello order",
"intents": [
{
"name": "AMAZON.FallbackIntent",
"samples": []
},
{
"name": "AMAZON.CancelIntent",
"samples": []
},
{
"name": "AMAZON.HelpIntent",
"samples": []
},
{
"name": "AMAZON.StopIntent",
"samples": []
},
{
"name": "CreateOrder",
"slots": [],
"samples": []
},
{
"name": "ProductIntent",
"slots": [
{
"name": "productType",
"type": "products"
}
],
"samples": [
"{productType}"
]
},
{
"name": "QuanityIntent",
"slots": [
{
"name": "quantiyValue",
"type": "AMAZON.NUMBER"
}
],
"samples": [
"{quantiyValue}"
]
},
{
"name": "AMAZON.YesIntent",
"samples": []
},
{
"name": "AMAZON.NoIntent",
"samples": []
}
],
"types": [
{
"name": "products",
"values": [
{
"name": {
"value": "burger"
}
},
{
"name": {
"value": "pizza"
}
}
]
}
]
}
}
}

How to write OR query with elastic search in node js

I have my document like this
Sample document,
[
{
"_index": "xpertdox",
"_type": "disease",
"_id": "Ectopic Heartbeat",
"_score": 24.650267,
"_source": {
"category": "Condition",
"name": "Ectopic Heartbeat",
"dui": "D005117",
"url_name": "Extrasystole"
}
},
This is my sample document.
if (req.param('disease')) {
searchString = req.param('disease');
filterQuery = { Category:
['disease','Condition','speciality','pharm','medicine'] };
} else if (req.param('docorhosp')) {
searchString = req.param('docorhosp');
filterQuery = { Category: ['hospital', 'doctor'] };
} else if (req.param('speciality')) {
searchString = req.param('speciality');
filterQuery = { Category: ['speciality'] };
}
client.search({
index: 'xpertdox',
type: 'disease',
size: 20,
body: {
query: {
must: {
match: {
name: {
query: searchString,
fuzziness: 2,
operator: "or"
}
}
},
filter : {
terms : filterQuery
}
}
}
}).then(function (resp) {
var data = resp.hits.hits;
if (isFromSsr) {
data = helper.prepareSearchDataForSsr(data);
}
res.json(data);
});
I am matching my parameter with name,but here I want to filter records only whose category is either 'doctor' or 'hospital'.How can devolope my query so to get my requirement..
Try this:
client.search({
index: 'dox',
type: 'disease',
size: 20,
body: {
query: {
must: {
match: {
name: {
query: req.param('disease'),
fuzziness: 2,
operator: "or"
}
}
},
filter: {
terms: {
category: ['hospital', 'doctor']
}
}
}
}
})

Indeterminate checkboxes with Vue.js

I just started out working with Vue and I'm trying to visualise a nested list.
The list-items should contain triple-state checkboxes:
When a child item is checked, the parent item's checkbox should become 'indeterminate'. When all child-checkboxes are checked, the parent checkbox should also become checked.
When a parent item checkbox is checked, all child item checkboxes (also the ones nested deeper) should be selected too.
I kind of have a working solution (check out this pen or the code below) but the checkbox-logic is still flawed. For this example, checked boxes are green, indeterminate ones are orange and unchecked ones are red.
I've run out of ideas how to fix it. Could someone shed some light on how to accomplish this in Vue?
'use strict';
Vue.component("book-chapter", Vue.extend({
name: "book-chapter",
props: ["data", "current-depth"],
data: function() {
return {
checked: this.data.checked,
indeterminate: this.data.indeterminate || false
};
},
methods: {
isChecked: function() {
return this.checked && !this.indeterminate;
},
isIndeterminate: function(){
return this.indeterminate;
},
toggleCheckbox: function(eventData) {
if (this.currentDepth > 0){
if (!this.data.children) {
this.checked != this.children
} else {
this.indeterminate = !this.indeterminate;
}
}
if (eventData) {
// fired by nested chapter
this.$emit('checked', eventData);
} else {
// fired by top level chapter
this.checked = !this.checked;
this.$emit('checked', {
data: this.data
});
}
},
isRootObject: function() {
return this.currentDepth === 0;
},
isChild: function() {
return this.currentDepth === 2;
},
isGrandChild: function() {
return this.currentDepth > 2;
}
},
template: `
<div class='book__chapters'>
<div
class='book__chapter'
v-bind:class="{ 'book__chapter--sub': isChild(), 'book__chapter--subsub': isGrandChild() }"
v-show='!isRootObject()'>
<div class='book__chapter__color'></div>
<div
class='book__chapter__content'
v-bind:class="{ 'book__chapter__content--sub': isChild(), 'book__chapter__content--subsub': isGrandChild() }">
<div class='book__chapter__title'>
<span class='book__chapter__title__text'>{{data.title}}</span>
</div>
<div class='book__chapter__checkbox triple-checkbox'>
<div class='indeterminatecheckbox'>
<div
class='icon'
#click.stop="toggleCheckbox()"
v-bind:class="{'icon--checkbox-checked': isChecked(), 'icon--checkbox-unchecked': !isChecked(), 'icon--checkbox-indeterminate': isIndeterminate()}">
</div>
</div>
</div>
</div>
</div>
<book-chapter
ref='chapter'
:current-depth='currentDepth + 1'
v-for='child in data.children'
key='child.id'
#checked='toggleCheckbox(arguments[0])'
:data='child'>
</book-chapter>
</div>
`
}));
Vue.component("book", Vue.extend({
name: "book",
props: ["data"],
template: `
<div class='book'>
<book-chapter
:data='this.data'
:currentDepth='0'>
</book-chapter>
</div>
`
}));
var parent = new Vue({
el: "#container",
data: function() {
return {
book: {}
};
},
mounted: function() {
this.book = {
"title": "Book",
"children": [{
"title": "1 First title",
"children": [{
"title": "1.1 Subtitle"
}, {
"title": "1.2 Subtitle"
}]
}, {
"title": "2 Second title",
"children": [{
"title": "2.1 Subtitle",
"children": [{
"title": "2.1.1 Sub-Sub title"
}, {
"title": "2.1.2 Another sub-sub title"
}]
}]
}]
}
}
});
Update: fixed a bug found by #PhillSlevin. See pen here
Check this pen, is it what you want to achieve?
I think you can use either eventbus or vuex to solve this problem,
if you treated every 's section as a component.
'use strict';
var bus = new Vue();
var book = {
"title": "Book",
"children": [{
"title": "1 First title",
"children": [{
"title": "1.1 Subtitle"
}, {
"title": "1.2 Subtitle"
}]
}, {
"title": "2 Second title",
"children": [{
"title": "2.1 Subtitle",
"children": [{
"title": "2.1.1 Sub-Sub title"
}, {
"title": "2.1.2 Another sub-sub title"
}]
}]
}]
};
Vue.component('book', {
template: `
<div class="book__chapter">
<p :class="'book__title ' + status" #click="clickEvent">{{title}} {{parent}}</p>
<book v-for="child in children" :key="child" :info="child"></book>
</div>
`,
props: ['info'],
data() {
return {
parent: this.info.parent,
title: this.info.title,
children: [],
status: this.info.status,
};
},
created() {
const info = this.info;
if(info.children) {
info.children.forEach(child => {
child.status = "unchecked";
// use title as ID
child.parent = info.title;
});
this.children = info.children;
}
},
mounted() {
const vm = this;
bus.$on('upside', (payload) => {
const targetArr = vm.children.filter((child) => child.title === payload.from);
if (targetArr.length === 1) {
const target = targetArr[0];
target.status = payload.status;
if (vm.children.every(ele => ele.status === 'checked')) {
vm.status = 'checked';
} else if (vm.children.every(ele => ele.status === 'unchecked')) {
vm.status = 'unchecked';
} else {
vm.status = 'indeterminate';
}
bus.$emit('upside', {
from: vm.title,
status: vm.status,
});
}
});
bus.$on('downside', (payload) => {
if (payload.from === this.parent) {
if (payload.status === 'checked') {
vm.status = 'checked';
vm.children.forEach(child => child.status = 'checked');
} else if (payload.status === 'unchecked') {
vm.status = 'unchecked';
vm.children.forEach(child => child.status = 'unchecked')
}
bus.$emit('downside', {
from: vm.title,
status: vm.status,
})
}
});
},
methods: {
clickEvent() {
if (this.status === 'checked') {
this.status = 'unchecked';
this.children.forEach(child => child.status = 'unchecked');
} else {
this.status = 'checked';
this.children.forEach(child => child.status = 'checked');
}
const vm = this;
bus.$emit('upside', {
from: vm.title,
status: vm.status,
});
bus.$emit('downside', {
from: vm.title,
status: vm.status,
});
},
}
});
var parent = new Vue({
el: "#container",
data: function() {
return {
book
};
},
});
.book__title.unchecked::after {
content: '□';
}
.book__title.indeterminate::after {
content: '△';
}
.book__title.checked::after {
content: '■';
}
.book__chapter {
display: block;
position: reletive;
margin-left: 40px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.2.6/vue.js"></script>
<div id="container">
<book :info="book" :parent="'container'"></book>
</div>

Categories