Can't dynamically connect to the `destruction` signal of dynamically created Item - qt

MyObj is the following component:
Item {
id:root
signal foo()
property string bar: "bar"
Component.onCompleted: root.foo()
}
When creating it dynamically via Qt.createComponent(...) -> comp.createObject(...) it is possible to connect JS functions to all signals, except destruction
Following code:
var comp = Qt.createComponent('MyObj.qml');
var finish = () => {
if(comp.status === Component.Error) {
console.log("Error loading component:", comp.errorString())
return
}
if(comp.status !== Component.Ready) {
console.log("Component not ready")
return
}
var obj = comp.createObject(mainWindow, {})
if(obj === null) {
console.log('Error creating object')
return
}
obj.foo.connect(() => console.log('foo!'))
obj.barChanged.connect(() => console.log('barChanged!'))
obj.destruction.connect(() => console.log('destruction!'))
}
if(comp.status !== Component.Loading)
finish();
else
comp.statusChanged.connect(finish);
produces the error:
qrc:/main.qml:32: TypeError: Cannot call method 'connect' of undefined
exactly at the line with obj.destruction.connect(...)
The documentation doesn't mention any such restriction.
What's wrong?
Putting:
Component.onDestruction: console.log("#destruction")
in MyObj works as usual, but that's not what I need.

I didn't realize JS needs the same syntax as QML for accessing properties of the superclass.
The following works just fine:
obj.Component.destruction.connect(() => console.log('destruction!'))

Related

RXJS Subscribe to a Subject - Actions must be plain objects. Use custom middleware for async actions

I'm trying to subscribe to a subject. This is working as expected the first time but throwing the above error the second time and I can't see where to fix it.
export function uploadSceneFile(action$, store) {
return action$.ofType(CREATE_SCENE_SUCCESS)
.mergeMap(({payload}) =>
UploadSceneWithFile(payload)
.map(res => {
if (res.progress > 0){
return { type: UPLOAD_SCENE_PROGRESS, scene: res }
}
else if(res.progress === -1){
return { type: UPLOAD_SCENE_SUCCESS, scene: res }
}
})
)
}
It's designed to listen for the scen being created, dispatch upload progress notifications and then dispatch the success message.
The error gets thrown straight away from this line the second time it runs
onProgress: (val)=> subject$.next({...scene,progress:val}),
export function UploadSceneWithFile(scene){
const subject$ = new Subject()
scene.filename = scene.file.name
scene.type = scene.file.type.match('image') ? 0 : 1
FileToScenePreview(scene).then(res => {
scene.thumbName = res.thumbName
})
const uploader = new S3Upload({
getSignedUrl: getSignedUrl,
uploadRequestHeaders: {'x-amz-acl': 'public-read'},
contentType: scene.file.type,
contentDisposition: 'auto',
s3path: 'assets/',
onError:()=>subject$.next('error'),
onProgress: (val)=> subject$.next({...scene,progress:val}),
onFinishS3Put: ()=> {
subject$.next({...scene,progress:-1})
subject$.complete()
},
})
uploader.uploadFile(scene.file)
return subject$.asObservable()
}
ERROR MESSAGE
Subscriber.js:242 Uncaught Error: Actions must be plain objects. Use custom middleware for async actions.
at Object.performAction (<anonymous>:1:40841)
at liftAction (<anonymous>:1:34377)
at dispatch (<anonymous>:1:38408)
at createEpicMiddleware.js:59
at createEpicMiddleware.js:59
at SafeSubscriber.dispatch [as _next] (applyMiddleware.js:35)
at SafeSubscriber../node_modules/rxjs/Subscriber.js.SafeSubscriber.__tryOrUnsub (Subscriber.js:238)
at SafeSubscriber../node_modules/rxjs/Subscriber.js.SafeSubscriber.next (Subscriber.js:185)
at Subscriber../node_modules/rxjs/Subscriber.js.Subscriber._next (Subscriber.js:125)
at Subscriber../node_modules/rxjs/Subscriber.js.Subscriber.next (Subscriber.js:89)
at SwitchMapSubscriber../node_modules/rxjs/operators/switchMap.js.SwitchMapSubscriber.notifyNext (switchMap.js:126)
at InnerSubscriber../node_modules/rxjs/InnerSubscriber.js.InnerSubscriber._next (InnerSubscriber.js:23)
at InnerSubscriber../node_modules/rxjs/Subscriber.js.Subscriber.next (Subscriber.js:89)
at MergeMapSubscriber../node_modules/rxjs/operators/mergeMap.js.MergeMapSubscriber.notifyNext (mergeMap.js:145)
at InnerSubscriber../node_modules/rxjs/InnerSubscriber.js.InnerSubscriber._next (InnerSubscriber.js:23)
at InnerSubscriber../node_modules/rxjs/Subscriber.js.Subscriber.next (Subscriber.js:89)
at MergeMapSubscriber../node_modules/rxjs/operators/mergeMap.js.MergeMapSubscriber.notifyNext (mergeMap.js:145)
at InnerSubscriber../node_modules/rxjs/InnerSubscriber.js.InnerSubscriber._next (InnerSubscriber.js:23)
at InnerSubscriber../node_modules/rxjs/Subscriber.js.Subscriber.next (Subscriber.js:89)
at MapSubscriber../node_modules/rxjs/operators/map.js.MapSubscriber._next (map.js:85)
at MapSubscriber../node_modules/rxjs/Subscriber.js.Subscriber.next (Subscriber.js:89)
at Subject../node_modules/rxjs/Subject.js.Subject.next (Subject.js:55)
at S3Upload.onProgress (uploadSceneFile.js:27)
at S3Upload.<anonymous> (s3upload.js:139)
In the inner map within your uploadSceneFile, you have an if statement followed by an else if statement, of if neither is true, the map will return undefined instead of an action.
.map(res => {
if (res.progress > 0){
return { type: UPLOAD_SCENE_PROGRESS, scene: res }
}
else if(res.progress === -1){
return { type: UPLOAD_SCENE_SUCCESS, scene: res }
}
// An action should be returned here!
})
Note that, when passed an undefined action, the check that Redux performs to determine whether or not an action is a plain object will effect the error you are seeing.

Meteor application - object appears in the terminal, but DATA appears undefined on the client side

import { Meteor } from 'meteor/meteor';
Meteor.methods({
'harmonized'(text){
HTTP.call( 'GET', 'https://hts.usitc.gov/api/search', { params: {
"query": text
}}, function( error, response ) {
if ( error ) {
console.log( error );
} else {
return response.data.results;
}
});
}
});
The above code gives me the array of objects in my terminal
import './shipping_steps.html';
import { HTTP } from 'meteor/http'
Template.shipping_steps.events({
// data: [],
'submit .hs': function(){
event.preventDefault();
//get Input value
const target = event.target;
const text = target.search.value;
//clear the form
target.search.value = "";
const data = Meteor.call('harmonized', text);
console.log(data);
return false;
}
})
When I try to store the array of objects on the client, I am not
able to do so and client logs out as undefined. However, for this
code, it is grabbing information from an input field on client
From your code data hasn't returned a value yet. You need to store the result on a reactive variable or a session variable.

How do i change "this" object

I know the rule that this object cant be changed but need an alternative method .
var that= this
axios.get('http://ec2-54-165-240-14.compute-1.amazonaws.com:3000/api/foodItem').then(function(data){
console.log("inside axios ",data)
that.setState({
items : data,
});
var curGroupId = that.props.cartReducer.val;
var items = that.state.items ;
var curItems= [];
for(var i in items){
if(items[i].food_group_id==curGroupId){
curItems.push(items[i]);
}
}
that.setState({
curItems : curItems
})
}).catch(function(err){
console.log(err)
})
I want to update the state in this object which is not accessible inside the then function and therefore i have stored this object in that before the function but i want to apply changes in the this object.
You can try using an arrow function, that way you will have access to this inside the inner functions.
axios.get('http://ec2-54-165-240-14.compute-1.amazonaws.com:3000/api/foodItem')
.then((data) => {
console.log("inside axios ",data)
this.setState({ // <---- references to the parent scope
items : data,
});
var curGroupId = that.props.cartReducer.val;
var items = that.state.items ;
var curItems= [];
for(var i in items){
if(items[i].food_group_id==curGroupId){
curItems.push(items[i]);
}
}
this.setState({ // this too ;)
curItems : curItems
})
}).catch((err) => {
console.log(err)
})
An arrow function will use the same scope as the parent function, pretty handy for these situations.
One more thing, I don't recommend calling setState multiple times. You should call it only once at the end of the callback, when all your data is ready to use.

Exception in delivering result of invoking method

I've been testing on http calls with meteor, I used nitrous (because I had no access to my dev laptop during the weekend) and it worked fine.
But when I tried to run from my local pc it returns:
Exception in delivering result of invoking 'getMatch': TypeError:
Cannot read property 'duration' of undefined.
Any ideas of what could be the cause?
Method definition:
Dota = {};
Dota.getMatch = function() {
if (!Meteor.settings.steamToken)
throw new Meteor.Error(500, 'Enter a valid Steam Token in Meteor.settings');
var matchResponse = Meteor.http.get(
"https://api.steampowered.com/IDOTA2Match_570/GetMatchDetails/V001/?",
{
params:{
"match_id": "1305454585",
"key": Meteor.settings.steamToken
}
}
);
if (matchResponse.statusCode === 200) {
return matchResponse.data.result
}
else {
throw new Meteor.Error(500, "getMatch failed with error: "+matchResponse.statusCode);
}
}
Meteor.methods({
'getMatch': function(){
return Dota.getMatch();
}
})
Calling the method:
Meteor.call('getMatch', function(error, result){
var duration = numeral(result.duration).format('00:00:00');
Session.set('duration', duration);
var winner = Meteor.myFunctions.getWinner(result.radiant_win);
Session.set('winner', winner);
});
Template.layout.helpers({
winner: function () {
return Session.get('winner');
},
duration: function () {
return Session.get('duration');
}
});
Found a solution, I changed the location of
Meteor.methods({
'getMatch': function(){
return Dota.getMatch();
}
})
to server/server.js (I had it in packages/dota/dota.js) and now it works! Thanks #user3374348 for helping!

Async call generates " Error: Can't wait without a "fiber", even with _wrapAsync

I've been having a problem using an RSS parser in meteor. It's an async call, so it needs ot be wrapped, however it still doesn't seem to work. I presume this is because the anonymous on('readable' function is outside the fiber, but I can't see how to resolve it.
var FeedParser = Meteor.require('feedparser');
var request = Meteor.require('request');
function getBlog(url, parameter, id){
request(parameter)
.on('error', function (error) {
console.error(error);
})
.pipe(new FeedParser())
.on('error', function (error) {
console.error(error);
})
.on('readable', function () {
var stream = this,
item;
while (item = stream.read()) {
Items.insert(new_item);
}
});
}
var wrappedGetBlog = Meteor._wrapAsync(getBlog);
Meteor.methods({
blog: function (url, parameter, id) {
console.log('parsing blog');
var items = wrappedGetBlog(url, parameter, id);
}
});
Meteor._wrapAsync() expects the wrapped function to return error and result to a callback. Your function, getBlog(), does not do that so _wrapAsync is not the right approach.
I have wrapped that function before but used a Future.
That approach allowed me to call feedparser from a Meteor.method(), which doesn't allow async functions, but you are also trying to do an insert inside the readable event. I think that insert will complain if it is not in a fiber. Maybe like this would also be necessary:
var r = request( parameter );
r.on( 'response' , function(){
var fp = r.pipe( new FeedParser() ); //need feedparser object as variable to pass to bindEnvironment
fp.on('readable', Meteor.bindEnvironment(
function () {
var stream = this,
item;
while (item = stream.read()) {
Items.insert(new_item);
}
}
, function( error ){ console.log( error );}
, fp // variable applied as `this` inside call of first function
));
});
Fibers is another option...
var Fiber = Npm.require( "fibers" );
.on('readable', function () {
var stream = this,
item;
while (item = stream.read()) {
Fiber( function(){
Items.insert(new_item);
Fiber.yield();
}).run();
}
});

Resources