How to get eval() to operate in the scope of QML element
-
If I have some JS code as text and I call it in eval(), I can then use the functions defined by this statement only in the scope of where the eval() occurred. As far as I can tell, this means that any new JS definitions created from the eval are invisible to the rest of QML. Consider this QML signal handler:
@
Item {
id: testitem
onThesourceChanged: {
eval(thesource)
testfunction()
}
}@The testfunciton() was defined in the text "thesource" and does indeed work; but it is not in the scope of the QML element and therefore cannot be called ever again, as far as I can see. I've tried various ideas like putting the eval() in a function, or inside Component.onCompleted, etc, but I can't seem to figure out how to get anything created by the eval() to be recognized as part of the parent QML element.
For example I want to be able to call testitem.testfunction() -- but it is not defined outside the scope of this handler.
Can anyone assist?
-
Hi, maybe a little bit far fetched, but the function might be garbage collected after you call it, since you just define it inside your "onThesourceChanged" slot and call it once, it seems like a local function in a function!? Just an idea :)
if you use eval your get somethging like this:
@
Item {
id: testitem
onThesourceChanged: {
var testfunction = function() { ... } // after eval -> local function ?
testfunction()
}
}
@ -
Well simple solution would be so save a reference to the function, so you can call it from outside, e.g.
@
Item {
id: testitem
property var testfunction // use this property to save the function you generate in your eval
onThesourceChanged: {
eval(thesource)
testfunction()
}
}
@
I can't think of any easier way at the moment, but if you only have once function you can do it like this, it gets a little more complicated if you generate multiple dynamic functions...
you can set the property from the source code your provide to eval or better return it in the source code ans use it like
@
testfunction = eval(thesource)
@
that should work, I have no idea if there is a way to define dynamic functions or properties in QML. Maybe you can research that or somebody else knows that, but I am not aware of something like that. -
Ok then I have another idea, if you load a whole script do you have control over it somehow? I mean you could wrap it inside a JS object and assign that to a property?
So same code as in my last post, just the property name changed
@
Item {
id: testitem
property var myFunctions // use this property to store your object with all functions
onThesourceChanged: {
myFunctions = eval(thesource)
myFunctions.testfunction()
}
}
@
and your "thesource" looks something like
@
return {
testfunction: function() { ... },
testfunction2: function() { ... },
testfunction3: function() { ... }
...
}
@Still this sounds a little weird, but I really have no idea if you can create dynamic functions property with QML. What you need is a JS lib maybe, like if you create a real .js file in QML and import it like
@
import "YourFunctions.js" as YourFunctions
@
again no idea if it would be possible to load a dynamically generated JS file like that, but that would be the best answer, if possible. And not assign the functions to a QML Item. -
A var needs to be in JSON format, right? If you have a JS file with normal standalone definitions, those will not be assigned to JSON keys, so you can't assign the entire file to a var. I wish you could, though.
My JS file is just a normal JS program. I cannot wrap it inside anything or assign each definition to a JSON key. I can import it in QML fine, but I want to be able to refresh this import dynamically, and using eval() seems to be one way to do this, if only I can get the scope to work out.
-
I don' think the "property var" needs to be in JSON format, since Qt 5 at least it can be any JavaScript value you can assign to a local "var". before Qt 5 you couldn't e event assign a function to a "property" as far as I know, but I have done that in my app (Qt 5.2.1).
Well maybe someone else has an idea with your problem, if you can't use it like this. :/