QML model link to JSON data - json

How to link a JSON stream to a QML model like you would do with angularJS?
In my QML, I have a Websocket object that receives data from a server:
WebSocket {
id: socket
url: "ws://3.249.251.32:8080/jitu"
onTextMessageReceived: { var jsonObject = JSON.parse(message) }
onStatusChanged:
if (socket.status == WebSocket.Error) { console.log("Error: " + socket.errorString) }
else if (socket.status == WebSocket.Open) { console.log("Socket open"); }
else if (socket.status == WebSocket.Closed) { console.log("Socket closed"); }
active: false
}
In this JSON I have something like:
{ items: [ "FOO", "BAR" ] }
Then I want to display two tabs, on titles FOO and the other, unsurprisingly, titled BAR.
This work great if I create a repeater that goes through the array in my model and create a tab for each entry:
TabView {
anchors.fill: parent
Repeater {
model: ListModel { id: tabs }
Tab {
title: Caption
Rectangle { color: "red" }
}
}
}
Up to now, this really looks like angularJs. I just need now to update my model (scope for angular) with the data received through the websocket.
For this, I have to add the tabs from my JSON to the ListModel as such:
...
onTextMessageReceived: {
var jsonObject = JSON.parse(message)
tabs.append(jsonObject.ITU.Modalities);
}
...
The problem is, each time I'll receive an update from JSON, tabs will be added. I don't want to clear the ListView each time, that would be time consuming I think. Is there a smart way to update the model from JSON smartly ? In angular, as they are both javascript structure, they are easy to merge. But here, I don't see an easy way.

Related

How would I find a JSON variable without knowing the parent variable names?

I need to set the displayName variable but I have no idea how to get to it. For context, I'm making a C# application to set this variable to something else. The parent variables to displayName vary depending on the user that is using this application.
I have blurred these as to not reveal any of my personal information.
I think I might need to loop through JSON object children, but I'm not sure.
Hey so you are correct you are going to have to iterate over the object and search through to find display name.
I wrote a little function below that will recursively go through the object and search for displayName. Obviously its hard if you never know the location or the pathname so you have to have a pretty open way to search the JSON object.
If you can control the way you are requesting the data maybe you could change the format so the data structure is more consistent, but I don't really know anything about where your getting the data from.
This is just one of the many ways to do it.
const obj = {
authenticationDatabase : {
accessToken: 'Mock',
profiles: {
displayName: 'THIS IS A MOCK USER NAME'
},
properties: [],
username: 'MOCK'
}
}
const obj2 = {
authenticationDatabase : {
accessToken: 'Mock',
profiles: {
deep: {
nested: {
object: {
displayName: 'THIS IS A MOCK USER NAME'
}
}
}
},
properties: [],
username: 'MOCK'
}
}
const findDisplayName = obj => {
if(!obj || typeof(obj) != 'object'){
return false;
}
if(Object.keys(obj).includes("displayName")){
return obj["displayName"]
}
for(const key in obj){
if(findDisplayName(obj[key])){
return findDisplayName(obj[key])
}
}
return false;
}
console.log(findDisplayName(obj))
console.log(findDisplayName(obj2))

How to show data in QML json request

So bear with me. How to create a model based on json? What is delegate?
Is below logic is correct?
Model -> delegate -> json request -> json get -> show to list view
In below code I can not see any data on screen. How to show data in QML json request?
thanks
UPDATED WORKING CODE:
import VPlayApps 1.0
import QtQuick 2.0
import QtQuick 2.3
import QtQuick.Controls 1.2
import "qrc:/"
Item {
id: item1
anchors.fill: parent
ListModel {
id: ***modelListIP***
}
ListView {
id: listview
anchors.fill: parent
model: ***modelListIP***
delegate: Text {
text: listdata
}
}
function getData() {
var xmlhttp = new XMLHttpRequest();
var url = "https://api.ipify.org?format=json";
xmlhttp.onreadystatechange=function() {
if (xmlhttp.readyState == XMLHttpRequest.DONE && xmlhttp.status == 200) {
myFunction(xmlhttp.responseText);
}
}
xmlhttp.open("GET", url, true);
xmlhttp.send();
}
function myFunction(response) {
var objValue = JSON.parse(response);
***modelListIP.append( {"listdata": objValue.ip })***
}
Button {
anchors.bottom: parent.bottom
width: parent.width
text: "Get Data"
onClicked: getData()
}
}
This tested on Qt5.9.2 using QML app project.
Your example is totally wrong.
JSON.parse() returns Object, not array. So you cannot call length() on it. Remember - {} - object, [] - array.
Your request returns something like {"ip":"111.111.111.111"}. Where do you see Name here? So you should append items model.append( {"listdata": arr.ip }), not like you do it now. Don't forget to surround the parameter name with quotes.
listview.model.append shoud be replaced with model.append. Learn what is Occam's razor.
model is not good id for item. Using reserved words is a bad style.
So I advice you to read documentation twice when you facing such problems.

Angular 4 httpclient mapping observable to nested json

With the help of the forum I was able to get my httpclient observable mapping issue sorted with this syntax;
this._http.get<DomainMetaData>(serviceURL);
which works great! However, I have a json response coming back from the server which is nested and wonder if I can use the same syntax as I'm currently using or if I need to now manually .map the response into my classes?
Based on posts I've seen here on SO I've created two classes to represent the nested structure of the response JSON (see below).
The function call...
getDomainMetaData(domain): Observable<DomainMetaData> {
let serviceURL = "http://localhost:3000/selectdomains?domain=" + domain;
return this._http.get<DomainMetaData>(serviceURL);
}
The classes...
export class DomainMetaDataAttr {
constructor(public name: string,
public value: string) {
}
}
export class DomainMetaData {
constructor(public name: string,
public attributes: DomainMetaDataAttr[]) {
}
}
An example of the json...
//DomainMetaData
// {
// "ResponseMetadata": {
// "RequestId": "11f000bf-0dff-8a2a-31ff-8631a9f25b5b",
// "BoxUsage": "0.0008183545"
// },
// "Items": [
// {
// "Name": "2",
// "Attributes": [
// {
// "Name": "Document Date",
// "Value": "22/03/13"
// },
// {
// "Name": "Document Ref",
// "Value": "Doc test"
// }
// ]
// },
I love the neatness and simplicity of my current solution but I appreciate I may now have to change my code!
Many Thanks.
If I understand correctly you want to know how to use the JSON response from an HttpClient call.
I currently approach it like this:
// x.service.ts
getData() {
return this.http.get(URL);
}
// x.component.ts
this.service.getData().subscribe(res => {
if (res['data']) {
const data = res['data'];
// do whatever with the data
}
});
With the above approach you can run whatever methods / filters you want on the JSON e.g. map over the array and pull data out / mutate it, etc. Not sure if it's necessary to create additional classes to deal with the nested JSON data.
Oops! The code I posted actually works, I just wasn't referencing the results in the attributes array correctly.
Thanks for taking the time to look at this.

Calling the JSON correctly

I have a JSON array fetched from the service to the controller. I'm able to display the JSON array in the console. But when a specific item from the JSON, is called it display's undefined. So how do I call it correctly so that I can use it in my view.
Controller:
$scope.onViewLoaded = function() {
callingService.getdata($scope.datafetched);
}
$scope.datafetched = function(response) {
debugger;
if (response) {
$rootScope.mainData = response;
$scope.localizeddataTypes = getLocalizedCollection($scope.mainData);
}
}
$scope.editFunction = function(key) {
console.log($scope.mainData);
debugger;
console.log($scope.mainData.keyValue);
}
Here console.log($scope.mainData); display's the JSON array but console.log($scope.mainData.keyValue); is displayed as undefined. And my JSON looks like
{
keyValue: "1234DEF56",
animals: {
name:"dog",
color:"brown"
},
birds:{
name:"canary",
color:"yellow"
}
}
So, how do I overcome this problem and why do I get it as Undefined.
Just a curiosity stuff. I feel that the content in that variable is stored in string format and not JSON or JavaScript Object. Try this, and see if that works?
$scope.mainData = JSON.parse($scope.mainData);
console.log($scope.mainData.keyValue);

Kendo MVVM Grid - Do I Need to Parse JSON Data?

I am having trouble getting JSON data to display in my grid. The html:
<div data-role="grid" data-bind="source: systems" data-columns='["SystemName", "SystemKey"]' ></div>
The mvvm view model:
var viewModel = kendo.observable({
isVisible: true,
systems: new kendo.data.DataSource({
schema: {
model: {
id: "system_id"
}
},
transport: {
read: {
url: "/api/HomeApi?method=Ref/Systems"
}
}
})
});
kendo.bind($("#systems"), viewModel);
The structure of the JSON Data:
- JSON
- Data
- Data
{}
SystemName=TIBCO
SystemKey=TIBCO
..... etc
Now, if the data were to come back in the following format, it would display fine:
[{ "SystemKey": "TIBCO", "SystemName": "TIBCO" }, { "SystemKey": "TIBCO", "SystemName": "TIBCO" }]
And yet, as stated, the actual data is in a more complex structure, rather than the simple structure above. So, do I have to parse this in some way, perhaps using schema.parse, to extract the SystemName and SystemKey, since it is down a few levels? Currently no data is displayed in the grid and I get "Uncaught TypeError: undefined is not a function " as an error.
The answer is yes, I do have to use schema.parse. This is what did it:
schema: {
parse: function (response) {
var systems = [];
for (var i = 0; i < response.Data.Data.length; i++) {
var system = {
SystemName: response.Data.Data[i].SystemName,
SystemKey: response.Data.Data[i].SystemKey
};
systems.push(system);
}
return systems;
}
}