skip to Main Content

Why do I get this error in the QML code: ReferenceError: m_jsonDocStr is not defined,
even if m_jsonDocStr is specified here in the C++ code:

Q_PROPERTY(QString m_jsonDocStr READ jsonDocToStr WRITE setJsonDocStr NOTIFY jsonDocStrChanged)

And why the QmlLink.open() C++ function is not opened from QML? (neither as a normal member function nor as a slot)

TypeError: Property 'open' of object [object Object] is not a function

Next, with the "<–" comment I point to the critical lines of the code, with the error messages I get.

This is the QML file:

/** Main.qml */

import QtCore
import QtQuick
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Dialogs
import QtQuick.Layouts
import main

ApplicationWindow {
    id: window
    width: 640
    height: 480
    visible: true
    title: qsTr("Data input widget")
    
    property string dataFilename: ""
    property string dataFile: ""
    
    menuBar: MenuBar {
        Menu {
            title: qsTr("&File")
            Action {
                text: qsTr("&Open...")
                onTriggered: fileDialog.open()
            }
        }
    }

    ScrollView {
        id: fileContents
        anchors.fill: parent
        property string dataFile: m_jsonDocStr  // <-- ReferenceError: m_jsonDocStr is not defined
        TextArea {
            text: "File: " + dataFilename + "n" + dataFile + "nLength: " + dataFile.length
        }
    }

    FileDialog {
        id: fileDialog
        title: "Open data file"
        nameFilters: ["JSON files (*.json)"]
        onAccepted: {
            dataFilename = selectedFile
            console.log("Open file: " + dataFilename)
            QmlLink.open(dataFilename)      // <-- TypeError: Property 'open' of object [object Object] is not a function
            console.log("File contents: " + m_jsonDocStr)
        }
        onRejected: {
            console.log("No file selected.")
        }
    }
}

Here is the header file:

/** QmlLink.hpp */

#ifndef QMLLINK_HPP
#define QMLLINK_HPP

#include <QObject>
#include <QJsonDocument>
#include <QtQml/qqmlregistration.h>

class QmlLink : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QJsonDocument m_jsonDoc READ jsonDoc WRITE setJsonDoc NOTIFY jsonDocChanged)
    Q_PROPERTY(QString m_jsonDocStr READ jsonDocToStr WRITE setJsonDocStr NOTIFY jsonDocStrChanged)
    QML_ELEMENT

public:
    explicit QmlLink(QObject *parent = nullptr);

public slots:
    QJsonDocument jsonDoc() const { return m_jsonDoc; }
    void          setJsonDoc(const QJsonDocument &jsonDoc) { m_jsonDoc = jsonDoc; }
    QString       jsonDocToStr() const { return m_jsonDoc.toJson(); }
    void          setJsonDocStr(const QString &jsonDoc) { m_jsonDoc = QJsonDocument::fromJson(jsonDoc.toUtf8()); }

signals:
    void jsonDocChanged();
    void jsonDocStrChanged();

public slots:
    void menuOpen();
    int  open(QString filePath);

private:
    QJsonDocument m_jsonDoc;
    QString m_jsonDocStr;

    QString m_jsonFileName = "default.json";
};

#endif // QMLLINK_HPP

This is the implementation file:

/** QmlLink.cpp */

#include "QmlLink.hpp"
#include <iostream> 
#include <QDebug>
#include <QFile>
#include <QQmlContext>
#include <QQmlEngine>
#include <QQuickView>

QmlLink::QmlLink(QObject *parent) : QObject{parent} {}

void QmlLink::menuOpen() {
    open(m_jsonFileName);
}

int QmlLink::open(QString filePath)
{
    m_jsonFileName = filePath;

    QUrl url(filePath);
    QFile jsonFile;
    jsonFile.setFileName(url.toLocalFile());

    if(jsonFile.open(QIODevice::ReadOnly) == false) {
        return -1;
    }

    const QByteArray data = jsonFile.readAll();
    m_jsonDoc = QJsonDocument::fromJson(data);

    const QString strDoc(m_jsonDoc.toJson(QJsonDocument::Compact));

    std::cout << "Data file contents: " << strDoc.toStdString() << std::endl;

    return 0;
}

This is a classic main() function:

/** main.cpp */

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>

#include "QmlLink.hpp"

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    QmlLink qmlLink;

    QQmlApplicationEngine engine;
    const QUrl url(u"qrc:/main/Main.qml"_qs);
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed,
        &app, []() { QCoreApplication::exit(-1); },
        Qt::QueuedConnection);
    engine.load(url);

    QQmlContext *rootContext = engine.rootContext();
    rootContext->setContextProperty("QmlLink", &qmlLink);

    return app.exec();
}

This is the trivial JSON file:

{
    "Array": [
        true,
        999,
        "string"
    ],
    "Key": "Value",
    "null": null
}

Tools versions:

  • Qt 6.5
  • OS: Linux
  • gcc 13.1
  • clang 15

2

Answers


  1. You should set the context property before loading the url :

    QGuiApplication app(argc, argv);
    
    QmlLink qmlLink;
    
    QQmlApplicationEngine engine;
    // set the context property here
    QQmlContext *rootContext = engine.rootContext();
    rootContext->setContextProperty("QmlLink", &qmlLink)
    
    const QUrl url(u"qrc:/main/Main.qml"_qs);
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed,
        &app, []() { QCoreApplication::exit(-1); },
        Qt::QueuedConnection);
    engine.load(url);
    

    and fix the Main.qml :

     // in ScrollView
     property string dataFile: QmlLink.m_jsonDocStr
     // ...
     // in FileDialog
     console.log("File contents: " + QmlLink.m_jsonDocStr)
    
    Login or Signup to reply.
  2. I think you can’t pass QJsonDocument from C++ to QML.
    As you mentioned you will get an "Unable to assign [undefined] to QString" error.
    But My Idea is to pass QByteArray.

    Here is my example:

    In main.cpp:

    #include <QApplication>
    #include <QQmlApplicationEngine>
    #include <QQmlContext>
    #include <QFileDialog>
    #include <QJsonDocument>
    #include <QJsonObject>
    #include <QDebug>
    
    class FileLoader : public QObject
    {
        Q_OBJECT
    
    public:
        explicit FileLoader(QObject *parent = nullptr) : QObject(parent) {}
    
    public slots:
        void openFile()
        {
            QString filePath = QFileDialog::getOpenFileName(nullptr, "Open JSON File", "", "JSON Files (*.json)");
    
            if (!filePath.isEmpty()) {
                QFile file(filePath);
                if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
                    QByteArray data = file.readAll();
                    file.close();
    
                    QJsonDocument jsonDoc = QJsonDocument::fromJson(data);
                    qDebug() << "JSON File Loaded:" << filePath;
                    emit fileLoaded(jsonDoc.toJson(QJsonDocument::Indented));
                }
            }
        }
    
    signals:
        void fileLoaded(const QByteArray &jsonData);
    };
    
    int main(int argc, char *argv[])
    {
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
        QApplication app(argc, argv);
    
        QQmlApplicationEngine engine;
    
        // Create an instance of the FileLoader
        FileLoader fileLoader;
    
        // Register the FileLoader as a context property
        engine.rootContext()->setContextProperty("fileLoader", &fileLoader);
    
        // Load the QML file
        const QUrl url(QStringLiteral("qrc:/QmlJson/Main.qml"));
        engine.load(url);
    
        return app.exec();
    }
    
    #include "main.moc"
    
    
    

    in Main.qml

    import QtQuick 2.15
    import QtQuick.Controls 2.15
    
    ApplicationWindow {
        visible: true
        width: 400
        height: 300
        title: "JSON Viewer"
    
        Text {
            id: jsonDataText
            anchors.centerIn: parent
        }
    
        Button {
            text: "Open JSON"
            onClicked: fileLoader.openFile()
        }
    
        Connections {
            target: fileLoader
            function onFileLoaded(jsonData) {
                jsonDataText.text = jsonData
            }
        }
    }
    
    

    This is my result:

    enter image description here

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search