How to invoke C++/Qt function from Javascript in QWebengine? - javascript

I have looked the Qt example about QWebChannel .
But its a C/S app. BTW it doesn't work on my computer(OS X 10.10.5, Qt5.5).
All my HTML contents come from local disk. I don't think it needs socket things.
new QWebChannel(navigator.qtWebChannelTransport, function(channel) {
// all published objects are available in channel.objects under
// the identifier set in their attached WebChannel.id property
var foo = channel.objects.foo;
// access a property
alert(foo.hello);
// connect to a signal
foo.someSignal.connect(function(message) {
alert("Got signal: " + message);
});
// invoke a method, and receive the return value asynchronously
foo.someMethod("bar", function(ret) {
alert("Got return value: " + ret);
});
});
There is no
navigator.qtWebChannelTransport
such a thing, JS stopped there.
What should I fill with the first parameter ?

For QtWebEngine, you have to use qt.webChannelTransport.

Related

Understanding JavaScript for TFS widget

I've been trying to modify the sample dashboard widget at this location
https://learn.microsoft.com/en-us/vsts/extend/develop/add-dashboard-widget?view=vsts#part-2-hello-world-with-vsts-rest-api
However, reluctantly have to admit I simply can't understand the structure required to extend it
Near the end, it uses "load: function" and returns the outputs of a REST API call, which I can consume however I want
However, I need to make more than one different REST call, and I simply cannot figure out how to get that info usable in my function
I modified the code so it starts like this:
VSS.require(["TFS/Dashboards/WidgetHelpers", "TFS/Work/RestClient","VSS/Service", "TFS/WorkItemTracking/RestClient" ],
I then created a handle for the other call I want to make like this:
var queryClient = VSS_Service.getCollectionClient(TFS_Wit_QueryAPI.WorkItemTrackingHttpClient);
var queryResults = queryClient.getQuery(projectId, "Shared Queries/My Bugs");
However, I cannot consume the contents of queryResults - I know it's working up to a point as if I put in an invalid URL it will error as it knows it can't access anything there. If the URL is correct, no matter what I've tried - even stringify just to see what comes back - I get 'undefined' or something similar (it's definitely a valid JavaScript object)
The key seems to be right at the end when you have "load: function" except that only allows one thing to be returned? The reason I know this is if I change the function that it returns to be the one I've written rather than the one from the sample, it works fine - but the problem remains the same in that I can only process the results of one API call.
You can call more than one APIs, the code in that article is just the simple sample.
For Widget extension, you just need to return the status (e.g. Success()) in load function, so you can return status at the end of the function. For example:
var getQueryInfo = function (widgetSettings) {
// Get a WIT client to make REST calls to VSTS
return TFS_Wit_WebApi.getClient().getQuery(projectId, "Shared Queries/Feedback")
.then(function (query) {
// Create a list with query details
var $list = $('<ul>');
$list.append($('<li>').text("Query ID: " + query.id));
$list.append($('<li>').text("Query Name: " + query.name));
$list.append($('<li>').text("Created By: " + (query.createdBy ? query.createdBy.displayName: "<unknown>") ));
// Append the list to the query-info-container
var $container = $('#query-info-container');
$container.empty();
$container.append($list);
// Use the widget helper and return success as Widget Status
return true;
}, function (error) {
// Use the widget helper and return failure as Widget Status
console.log(error);
return false;
});
}
var getAnOhterQueryInfo = function (widgetSettings) {
// Get a WIT client to make REST calls to VSTS
return TFS_Wit_WebApi.getClient().getQuery(projectId, "Shared Queries/Bug")
.then(function (query) {
// Create a list with query details
var $list = $('<ul>');
$list.append($('<li>').text("Query ID: " + query.id));
$list.append($('<li>').text("Query Name: " + query.name));
$list.append($('<li>').text("Created By: " + (query.createdBy ? query.createdBy.displayName: "<unknown>") ));
// Append the list to the query-info-container
var $container = $('#query-info-container');
$container.empty();
$container.append($list);
// Use the widget helper and return success as Widget Status
return true;
}, function (error) {
// Use the widget helper and return failure as Widget Status
console.log(error);
return false;
});
}
return {
load: function (widgetSettings) {
// Set your title
var $title = $('h2.title');
$title.text('Hello World');
var r1= getQueryInfo(widgetSettings);
var r2=getAnOhterQueryInfo(widgetSettings);
if(r1==true && r2==true){
return WidgetHelpers.WidgetStatusHelper.Success();
}else{
return WidgetHelpers.WidgetStatusHelper.Failure("failed, check error in console");
}
}

Get a value from a promise chain in another class

I am trying to get the value of a queried ID called from another class however when I call the function it gives me a promise chain and not the value I am looking for.
The method in the class 'Helper' is below
function querySF() {
var conn = new jsforce.Connection({
// you can change loginUrl to connect to sandbox or prerelease env.
loginUrl: 'https://www.salesforce.com'
});
return conn.login('someusername', 'password')
.then(function(userInfo) {
// Now you can get the access token and instance URL information.
// Save them to establish connection next time.
console.log(conn.accessToken);
console.log(conn.instanceUrl);
// logged in user property
console.log("User ID: " + userInfo.id);
console.log("Org ID: " + userInfo.organizationId);
// ...
return conn.query("SELECT Id FROM some place Where name = 'some name'")
})
.then(function(result) {
console.log("total : " + result.totalSize);
console.log("fetched : " + result.records.length);
// is returning the id
console.log(result.records[0].Id);
return result.records[0].Id; // can see the id here when debugging
})
.catch(function(err) {
console.error(err);
});
}
I am exporting the module like this at the bottom of the class:
exports.querySF = querySF();
The other class called 'BookingEvent' calls the method like this: var theId = Helper.querySF; and it returns a promise, I have printed the promise to console console.log(Helper.querySF); to see the results:
Promise {
_45: 0,
_81: 1,
_65: 'a0L46111001LyvsEAC', // This is the value I need
_54: null,
then: [Function],
stream: [Function: createRequest] }
It was thought that I should be able to just use
helpers.querySF().then(function(value){
console.log(value);
})
and be able to get the value however I am getting this error:
Failed: helpers.querySF is not a function
I am quite new to promises and no one at my company can seem to solve the issue. I have research many different ways of resolving promises however they do not work and I also do not understand. Could someone help me resolve this promise so the id accessible whenever I call this method, which will be multiple times with different queries I will be sending in.
If the promises are not related each other, you may find better Promise.all() here instead of chaining promises in this way. Then resolve all of them. If actually you get the name of the second query from the first promise, actually you need to chain them.
Then you are missing a catch in order to catch errors for the first promise.
And maybe a refactor using function may help the code to look better.
return conn.login('someusername', 'password')
.then(elaborateUserInfo)
.catch(catchErrors)
.then(elaborateResults)
.catch(catchErrors);
function elaborateUserInfo(userInfo) {
// Now you can get the access token and instance URL information.
// Save them to establish connection next time.
console.log(conn.accessToken);
console.log(conn.instanceUrl);
// logged in user property
console.log("User ID: " + userInfo.id);
console.log("Org ID: " + userInfo.organizationId);
// ...
return conn.query("SELECT Id FROM some place Where name = 'some name'");
}
function elaborateResults(result) {
console.log("total : " + result.totalSize);
console.log("fetched : " + result.records.length);
// is returning the id
console.log(result.records[0].Id);
return result.records[0].Id; // can see the id here when debugging
}
function catchErrors(err) {
console.log(err);
}
It looks better, doesn't it?
Instead, the only reason for this error Failed: helpers.querySF is not a function is that you don't have that method in your object. Are you sure you really exported it in order to be visible outside your module?

How to dynamically create and populate multiple objectStores on HTML5 IndexedDB in the same transaction?

Working on the IndexedDB API, I'm creating many objectStores that belong to the same database, in one transaction, when the user loads a webpage.
I order to do so, I created an object which contains many objectStores to be created, each one has it's name, data and index.
Then a function runs the object and effectively creates Database, objectStores and indexes for each one.
However of all OS's created, just the last member of the object gets populated. Say of 5 objects to be created and populated, 5 are created but only the last one is populated.
Clearly is a problem of overwriting or some issue related to the JS stack or asynchronicity.
I appreciate any help to make the code populate all OS not the last one.
My browser is Chrome 56, I fetch data from an API whose response is OK, and I'm coding on vanillajs. I appreciate your help in vanillajs, there is no way to use any library or framework different from what the modern Web Platform offers.
Here is the code:
On the HTML side, this is an example of the object:
var datastores = [{osName:'items', osEndpoint: '/api/data/os/1/1', osIndex:'value'}, {osName:'categories', osEndpoint: '/api/data/os/2/1', osIndex: 'idc'}];
On javascript:
var request = indexedDB.open(DB_NAME, DB_VERSION); // open database.
request.onerror = function (e) { // error callback
console.error("error: " + e.target.errorCode);
};
request.onupgradeneeded = function (e) { // the onupgradeneeded event which creates all schema, dataabase, objectstores and populates OS.
var db = this.result;
for (var i in datastores) { // loop the objectStore object.
var objectStore = db.createObjectStore(datastores[i].osName, {keyPath: "id"});
TB_NAME = datastores[i].osName; // instantiate each objectStore name.
objectStore.createIndex(datastores[i].osIndex, datastores[i].osIndex, { unique: false }); // create each index.
objectStore.transaction.oncomplete = function(e) { // oncomplete event, after creating OS...
fetchGet(datastores[i].osEndpoint, popTable); // runs a function to fetch from a designated endpoint and calls a function.
};
}
}
Now the functions: to fetch data and to populate data:
function fetchGet(url, function) { // fetch from API.
fetch(url, {
method: 'GET'
}).then(function(response) {
return response.json();
}).then(function(json) {
popTable (json);
}).catch(function(err) {
console.log('error!', err);
});
}
function popTable(json) {
var m = 0;
var tx = db.transaction(TB_NAME, "readwrite");
tx.oncomplete = function(e) {
console.log("Completed Transaction " + TB_NAME);
};
tx.onerror = function(e) {
console.error("error: " + e.target.errorCode);
};
var txObjectStore = tx.objectStore(TB_NAME);
for (m in json) {
var request = txObjectStore.add(json[m]);
request.onsuccess = function (e) {
console.log('adding... ' );
};
}
}
The for (var i in datastores) loop runs synchronously, updating the global TB_NAME variable every time. When the loop finishes, TB_NAME will be holding the name of the last object store.
By the time the asynchronous popTable calls run, TB_NAME will forever be holding the name of the last store, so that's the only one that will update. Try adding logging to popTable to see this.
You'll need to pass the current value of the store name along somehow (e.g. as an argument to fetchGet). Also note that although you pass popTable as a parameter when calling fetchGet you're not actually accepting it as an argument.
...
Specific changes:
Change how you call fetchGet to include the store name:
fetchGet(datastores[i].osEndpoint, popTable, datastores[i].osName);
Change the fetchGet function to accept the args:
function fetchGet(url, func, name) {
And then instead of calling popTable directly, do:
func(json, name);
And then change the definition of popTable to be:
function popTable(json, name) {
... and use name in the transaction.

Socket.io - Variables Not Updating Outside socket.on

I am working with Socket.io and MongoDB. When I first send my socket.emit to the server, the server takes in the parameter and returns with my desired output. When I reach the socket.on on my client.js the OrderID is shown to the console. Yet when I exit the socket.on method block, the GenOrderID variable becomes undefined.
My question is: why are variables that were created before the socket.on, no longer accessible outside it.
Here is the client.js I am working with:
// Create order array
var Order = [];
// Create GeneratedOrderID variable
var GenOrderID;
// Get School ID from cookie
var SchoolID = getCookie("SchID");
// Generate OrderID
socket.emit('GenerateOrderID', SchoolID);
socket.on('GenerateOrderID', function(GeneratedOrderID) {
console.log("OrderID sent from server is: " + GeneratedOrderID); // This returns the desired number
GenOrderID = GeneratedOrderID;
});
Order[0] = GenOrderID;
console.log("GenOrderID is: " + GenOrderID); // This returns undefined
console.log("Order[0] is: " + Order[0]); // This returns undefined
Here is the server.js I am working with:
socket.on('GenerateOrderID', function(PassSchoolID) {
// Connect to database
MongoClient.connect('mongodb://localhost:27017/Orders', function(err, db) {
// Handle errors
assert.equal(null, err);
console.log("Begin creation of OrderID");
db.collection('Orders').find({SchoolID: PassSchoolID}).sort({amount: -1}).limit(1).forEach(function (result) {
var GeneratedOrderID = parseInt(result.OrderID);
GeneratedOrderID++;
console.log("The server says the OrderID is: " + GeneratedOrderID); // This returns the desired number
// Return to client
socket.emit('GenerateOrderID', GeneratedOrderID);
});
});
});
By placing the console.log() inside the socket.on I was able to have it work properly.
// Create order array var
Order = [];
// Create GeneratedOrderID variable
var GenOrderID;
// Get School ID from cookie
var SchoolID = getCookie("SchID");
// Generate OrderID
socket.emit('GenerateOrderID', SchoolID);
socket.on('GenerateOrderID', function(GeneratedOrderID) {
console.log("OrderID sent from server is: " + GeneratedOrderID);
GenOrderID = GeneratedOrderID;
Order[0] = GenOrderID;
console.log("GenOrderID is: " + GenOrderID);
console.log("Order[0] is: " + Order[0]);
});
You're setting the value of GenOrderID inside a callback function, which is only executed once a GenerateOrderId event has occurred. The code inside of a callback function doesn't run until that function is called.
For example:
function run(f) {
// call `f` after 1 second
setTimeout(f, 1000);
};
var foo;
run(function() {
foo = 'bar';
console.log('in callback:', foo);
});
console.log('before callback:', foo);
// output:
// before callback: undefined
// in callback: 'bar'
At some point in the future, foo will equal 'bar', but you can only know this is the case after your callback has been called. And you can only know that your callback has been called from inside it.

Breeze Type Error: object is not a function

I have a EF Code-First DB, with 3 important Tables. Share, ContactDetail and Owner. The Share and the Owner Tables both have the Contact Detail as navigational property, but the Share Table has both ContactDetail and Owner as navigational properties.
I have a simple controller Get that retrieves the Shares
[HttpGet]
public IQueryable<Share> VesselShares()
{
return _cp.Context.Shares;
}
and the breeze call is:
getVesselShares = function (vId) {
var query = EntityQuery.from('VesselShares')
.expand('Owner, ContactDetail')
.where('VesselId', filterQueryOp.Equals, vId)
.orderBy(orderBy.share);
return manager.executeQuery(query)
.then(querySucceeded)
.fail(queryFailed);
function querySucceeded(data) {
return vesselShares(data.results);
}
}
When I load my page, with some other data:
return ctx.getVesselById(vId, vessel).then(function () {
ctx.getVesselShares(vId).then(function() {
logger.log('Data Loaded: ' + ctx.vesselShares().length, 'shipdetail', 'Ship', true);
});
////Load all the details before activating the other child pages
//return Q.all([
// //ctx.getVesselShareOwners(vId, dbShareOwners),
// //ctx.getVesselVesselBuilders(vId),
// //ctx.getVesselAlterations(vId),
// //ctx.getVesselInsurers(vId),
// //ctx.getVesselClassifSocieties(vId),
// ctx.getVesselShares(vId)
//]).then(function () {
// //shareOwners(utils.consolidateShares(dbShareOwners()));
// logger.log('Data Loaded: ' + ctx.vesselShares().length, 'shipdetail', 'Ship', true);
// //register.shareOwners(shareOwners());
// //ctx.vesselShareOwners(shareOwners());
// ////Can only Register when all 64 Shares are occupied
// //ctx.canRegisterVessel(dbShareOwners().length === 64);
//});
});
The first call to retrieve the Shares work fine, but oddly the 2nd call and subsequent calls throw an error on the ctx.getVesselShares method.
"TypeError: object is not a function" .
I was able to track down the error to this line of code in the breeze.debug.js...
proto.getProperty = function (propertyName) {
return this[propertyName]();
};
This method is expecting a ContactDetail observable but strangely breeze doesn't come with an observable on those subsequent calls.
This error happens whenever I want to saveChanges or retrieve records on the Share Table. I'm running the latest breeze, MVC 5, Web Api 2.
Any help will be greatly appreciated, this is driving me crazy.
Thanks.

Categories