Cannot append to JS object in HighCharts callback, in Vue - json

I am using Vue 3.9.3, along with highcharts-vue 1.3.5 . I am trying to put into an object each highchart, as it loads, so then I have access to any chart I want like
myCharts.aChart or
myCharts.anotherChart,
so I can easily do myCharts.anotherChart.addData
In practice I do,
<highcharts :constructor-type="'stockChart'" :options="options" :callback="chartcallback" ></highcharts>
and then
data(){
return{
charts:{}
}
},
methods:{
chartcallback(hc){
let obj = {[hc.options.id] : hc};
this.charts = Object.assign(this.charts, obj);
//also tried this
const newChart = {id:hc.options.id, chart : hc};
this.$set(this.charts, newChart.id, newChart);
//also tried this
this.charts = Object.assign({}, this.charts, {
[hc.options.id] : hc
});
//also tried this
this.charts[hc.options.id]= hc;
console.log('test ', this.charts);
}
}
and then I would watch my data and each time they change, I would add data to each highchart,
watch: {
myData: {
immediate: true,
deep: true,
handler(){
this.charts.NameChart.series[0].setData(this.myData[0], true);
this.charts.DrinkChart.series[0].setData(this.myData[1], true);
//etc....
this.charts.NameChart or this.charts.DrinkChart should be constructed in chartcallback and NameChart, DrinkChart is the value of hc.options.id hc.options.id always has a value and it is there, I checked.
The problem is
at the end of chartcallback where I do console.log('test ', this.charts);, the produced obj is
//first time
{NameChart:chart}
//second time
{NameChart:chart}
but it should be
//first time
{NameChart:chart}
//second time
{NameChart:chart,
DrinkChart:chart}
It looks like it overwrites the this.charts every time chartcallback is called. I tried several methods, as I note, but nothing works.
What can I do ?
Thanks

Related

Trying to use local-storage in react app, however not working in between pages

I'm trying to save an array to local-storage in my react app, so that if the user goes to another page in the app, or closes the app and reopens it, the value stays the same.
In my index.js (simplified code):
import ls from 'local-storage';
function HomeIndex() {
const [testString, setTestString] = useState(ls('localStorageText') || '');
if(condition){
const array = [1,2,3];
const saveArray = {key: array};
localStorage.setItem('key1', JSON.stringify(saveArray));
const restoreValue = localStorage.getItem('key1');
setTestString(JSON.parse(restoreValue).key);
}
return (
<div className="col-12">
{testString}
</div>
);
}
When I press the button, and the condition is met, the testString value displays 123 as it should. And it holds the value. However it does not work when I try and add my own array.
const array = reversedHistoryText;
const saveArray = {key: array};
localStorage.setItem('key1', JSON.stringify(saveArray));
const restoreValue = localStorage.getItem('key1');
setTestString(JSON.parse(restoreValue).key);
It doesn't display anything the first time the button is clicked, then gives error on the 2nd time:
Error: Minified React error #31;
When I do this test:
setTestString(JSON.stringify(reversedHistoryText));
The result is []
You need to set your testString to the localStorage value.
import ls from "local-storage";
import React, { useEffect, useState } from "react";
function MyComponent() {
const [testArray, setTestArray] = useState([]);
useEffect(() => {
setTestArray(ls("testArray") || []);
}, []);
function handleClick(e) {
ls("testArray", [
{ id: 1, name: "this" },
{ id: 2, name: "thing" },
{ id: 3, name: "is" },
{ id: 4, name: "cool" }
]);
setTestArray(ls("testArray"));
}
return (
<div className="col-12">
<ul>
{testArray.map(obj => (
<p key={obj.id}>{obj.name}</p>
))}
</ul>
<button onClick={handleClick}>Set The State</button>
</div>
);
}
export default MyComponent;
You don't need to use third party for localStorage.
Just use localStorage without importing anything.
To save,
localStorage.setItem('key', 'value');
To get value from localStorage,
localStorage.getItem('key') // value
To remove value,
localStorage.removeItem('key')
Use
if(condition) ls('localStorageText', "TEST");
setTestString(ls('localStorageText')|| ' '); }
Instead
if(condition){ ls('localStorageText', "TEST");
setTestString(ls('localStorageText')); }
Because when you go back to the index page a new instance of this component is rendered and i think the condition in the if statement is false, so the code don't change the setstate value...
To set use
localStorage.setItem('itemName', JSON.stringify(arrayName));
To get use
whatEver = jQuery.parseJSON(localStorage.getItem('itemName'));
Local storage stores strings

basic reducer possibly mutating app state

I am using Redux spread operator to hopefully mantain the state as immutable objects.
However, i am managing to make the most simple unit test fail.
I assume the error probably has to do with immutables, but am i not using the spread operator correctly?
Here is my unit test:
describe('app logic', () => {
it('initialises app', () => {
const newState = reducer(INITIAL_STATE, {type: "NEXT"})
const expectState = {
start: true,
render_component: null,
requests: {},
results: {},
}
console.log('newState', newState)
console.log('expected state', expectState)
expect(newState).to.equal(expectState)
})
})
and here is my reducer
export const INITIAL_STATE = {
start: false,
render_component: null,
requests: {},
results: {}
}
export const next = (state) => {
if (state === INITIAL_STATE) {
return {
...state,
start: true,
}
}
return state
}
export function reducer(state = INITIAL_STATE, action) {
switch (action.type) {
case 'NEXT':
return next(state)
default:
return state
}
}
I print the two objects, and they look the same.
i get the error :
1) app logic initialises app:
AssertionError: expected { Object (start, render_component, ...) } to equal { Object (start, render_component, ...) }
Not sure exactly which testing library you are using, but usually a name like .equal is used to test strict equality ( === ), which means (at least in the case of objects) that the two things being compared must actually reference the exact same object. So, for example,
const original = { a: 1 }; // creates a new object, assign it
const testMe = { a: 1 }; // creates another new object, assign it
console.log( original === testMe ) // false
evaluates to false, because while the objects have the same content, they do not reference the exact same object. They are separate, independently created, objects that happen to have the same content. Compare that to
const original = {a: 1}; // create a new object
const testMe = original; // create another reference to the same object
console.log( original === testMe ); // true
So when you return
return {
...state,
start: true,
}
you are creating and returning a new object, so it naturally can not reference the same object that you created and assigned to the variable name expectedState.
If what you are interested in is not strict equality, but rather just that the content in the two objects are the same, there exists other methods than .equal, usually named something with deep (since they go deep into the objects/arrays/whatever to check if the values are the same).
Chai.js has examples of both expect(x).to.equal(y) and expect(x).to.deep.equal(y) in their docs: http://chaijs.com/api/bdd/#method_equal
Your testing library probably has very similar, if not identical, syntax.

Variable scope & Callback woes

This program is reading through the nested object searching for a specific key & values. Once this data is found it has to initiate callback to send back the data. The object looks like this:
{
"name": "joel",
"title": "CTO",
"edu": {
"school": "RMB",
"college": "GNK",
"pg": "CDAC",
"extract": "This is a large text ..."
}
}
Here as I come from synchronous programming background I am not able to understand when I have to initiate the callback and also ensure variables are in scope
function parseData(str, callback) {
function recursiveFunction(obj) {
var keysArray = Object.keys(obj);
for (var i = 0; i < keysArray.length; i++) {
var key = keysArray[i];
var value = obj[key];
if (value === Object(value)) {
recursiveFunction(value);
}
else {
if (key == 'title') {
var title = value;
}
if (key == 'extract') {
var extract = value.replace(/(\r\n|\n|\r)/gm," ");
callback(null, JSON.stringify({title: title, text: extract}));
}
}
}
}
recursiveFunction(str, callback(null, JSON.stringify({title: title, text: extract})));
};
when this code is executed we get following error
/parseData.js:29
recursiveFunction(str, callback(null, JSON.stringify({title: title, text: extract})));
^
ReferenceError: title is not defined
Okay. So you want a function that retrieves the first property named title and the first property named extract from a nested object, no matter how deeply nested these properties are.
"Extract a property value from an object" is basically is a task in its own right, we could write a function for it.
There are three cases to handle:
The argument is not an object - return undefined
The argument contains the key in question - return the associated value
Otherwise, recurse into the object and repeat steps 1 and 2 - return according result
It could look like this:
function pluck(obj, searchKey) {
var val;
if (!obj || typeof obj !== "object") return;
if (obj.hasOwnProperty(searchKey)) return obj[searchKey];
Object.keys(obj).forEach(function (key) {
if (val) return;
val = pluck(obj[key], searchKey);
});
return val;
}
Now we can call pluck() on any object and with any key and it will return to us the first value it finds anywhere in the object.
Now the rest of your task becomes very easy:
var obj = {
"name": "joel",
"title": "CTO",
"edu": {
"school": "RMB",
"college": "GNK",
"pg": "CDAC",
"extract": "This is a large text ..."
}
}
var data = {
title: pluck(obj, "title"),
text: pluck(obj, "extract")
};
This function that you 've posted above has nothing to do with async programming. I will respond in the context of the chunk of code that you 've posted. The error that you have is because you are calling the recursiveFunction(str, callback(null, JSON.stringify({title: title, text: extract}))); but the title variable is nowhere defined. I can see a definition of the title but it is in the the context of the recursiveFunction function. The variables that you define in there are not visible outside of the scope of that function and that's why you have this error.
You are trying to do something strange in this line:
recursiveFunction(str, callback(null, JSON.stringify({title: title, text: extract})));
This line will invoke the callback and will pass in the recursiveFunction the results of this function. I would expect to see something like that in this line:
recursiveFunction(str, callback);

Unable to sort Dgrid

var CustomGrid = declare([Grid, Keyboard, Selection]);
var questionGrid = new CustomGrid({
store: questionCacheStore,
columns: [
editor({
label: "Questions",
field: "question",
editor: "text",
editOn: "dblclick",
sortable:true})
],
selectionMode: "single",
cellNavigation: false
}, "questions");
I am new to Dgrid. So, please do bear with me .
i was able to populate the dgrid with a JsonStore content. But when i click on the column 'Questions', it doesn't get sorted as in local data store.instead it shows an error Uncaught TypeError: Object [object Object] has no method 'sort'. Is it required to define such a method . If so, how and where should i define it ?
I am not the person to answer your J2EE question. I asked that question recently. The solution that I found was to inject the HttpServletRequest directly. This allowed me access to the query string parameters. From there I was able to get the sort direction (ascending, descending) and column to sort. Hopefully the snippets below will help.
Example Grid Setup
require(["dojo/store/JsonRest", "dojo/store/Memory", "dojo/store/Cache",
"dojo/store/Observable", "dgrid/OnDemandGrid", "dojo/_base/declare", "dgrid/Keyboard",
"dgrid/Selection", "dojo/domReady!"],
function(JsonRest, Memory, Cache, Observable, Grid, declare, Keyboard, Selection) {
var rest = new JsonRest({target:"/POC_Admin/rest/Subcategory/", idProperty: "subcatId"});
var cache = new Cache(rest, new Memory({ idProperty: "subcatId" }));
var store = new Observable(cache);
var CustomGrid = declare([ Grid, Keyboard, Selection ]);
var grid = new CustomGrid({
columns: {
subcatId: "ID",
name: "Name"
},
store: store
}, "grid");
grid.on("dgrid-select", function(event){
// Report the item from the selected row to the console.
console.log("Row selected: ", event.rows[0].data);
});
grid.startup();
});
Example Rest GET
#Context private HttpServletRequest servletRequest;
#GET
#Path("")
#Produces(MediaType.APPLICATION_JSON + ";charset=UTF-8")
public String getSubcategories(#QueryParam("name") String name) throws IOException {
//Respond to a QueryString value.
if (servletRequest.getQueryString() != null && servletRequest.getQueryString().length() > 0) {
String querystringKey = servletRequest.getQueryString();
System.out.println("QSKey = " + querystringKey);
System.out.println("Substr: " + querystringKey.substring(0, 4));
if (querystringKey.length()>4) {
if (querystringKey.substring(0, 4).contains("sort")) {
//We have the sort request.
}
}
}
//Return all results otherwise from your DAO at this point
}

Json and lawnchair usage

i saw below example in lawnchair documentation,
var store = new lawnchair({name:'testing'}, function(store) {
// create an object
var me = {key:'brian'};
// save it
store.save(me);
// access it later... yes even after a page refresh!
store.get('brian', function(me) {
console.log(me);
});
});
i am not sure i understood it correctly or not, but based on my understanding, i wrote code like this, (name,dtime,address are variables with value)
db = Lawnchair({
name : 'db'
}, function(store) {
console.log('storage open');
var formDetails = {
"candidateName" : name,
"DateTimeOfVerification" : dtime,
"ResidentialAddress" : address
}
store.save({key:"fdetails",value:formDetails});
store.get("fdetails", function(obj) {
alert(obj);
});
});
but, in alert i did not got value, i got "[object Object]".
1) how to store multi-attribute json object in lawnchair
2) how to get that json object.
Try this:
db = Lawnchair({name : 'db'}, function(store) {
console.log('storage open');
var formDetails = {
"candidateName" : "Viswa",
"DateTimeOfVerification" : "30/07/2012",
"ResidentialAddress" : "3 The Road, Etcc...."
}
store.save({key:"fdetails", value:formDetails});
store.get("fdetails", function(obj) {
console.log(obj);
alert(obj.value.candidateName);
alert(obj.value.DateTimeOfVerification);
alert(obj.value.ResidentialAddress)
});
});
1) You are storing the formDetails structure correctly.
2) obj.value is the collection you are looking for
Had you added the console.log(obj); line into your code and then inspected the console you could probably have worked this out for yourself.