I'm working at an application in Titanium Studio. I have an MVC infrastructure implemented, and in a controller I want to get some data from the Cloud and only after that to call the view. The code is similar to this.
Default : function() {
Cloud.Objects.query({
classname : 'Customer',
}, function(e) {
if (e.success) {
Ti.API.info('aci ' + e.Customer);
favorites = e.Customer;
return this.view("Default", favorites);
} else {
alert('Error:\\n' + ((e.error && e.message) || JSON.stringify(e)));
}
});
},
}
The thing is, that the first function has to return "this.view("Default", favorites);", not the callback from the query. Also, the query function is asyncronus and I have to wait for the data, and only then call the view.
Do you have any ideas?
Thank you
Create an even handler for some custom event like receiveCustomer.
When customer retrieved, fire the event receiveCustomer and set customer as event data or initialize some variable outside the callback with retrieved data (but in this case before event triggering). In event hander onReceiveCustomer get the customer from the event data or from that variable and render the view.
Related
I have this function code in my vue component methods that will remove the customers data if a button is clicked and show a chrome notification.
deleteCustomer(id) {
console.log('deleting customer:' + id);
db.customers.delete(id).then( () => {
console.log('customer '+ id +' deleted!');
browser.notifications.create('deleted',{
type: 'basic',
iconUrl: 'icons/128.png',
title: 'Data removal',
message: 'data removed with success!'
});
this.viewCustomers();
});
},
At the end of the function I'm calling another method that is supposed to call a dexie.js instance to show in a table all the customers data that are stored. When the component is mounted, all work fine with the viewCustomers function and the table is populated correctly. What I need to fix is that the method is not called after data deletion and the table isn't updating. How I can fix this, is there a vue function I can use or any code modification that can solve this problem?
As mentioned in the docs, Delete items is actually an async call which means it calls the this.viewCustomers() before the item is even deleted, thus it seems that it is not working. The easiest way to resolve this is to use async/await like:
async deleteCustomer(id) {
console.log('deleting customer:' + id);
await db.customers.delete(id);
console.log('customer ' + id + ' deleted!');
browser.notifications.create('deleted', {...});
this.viewCustomers();
},
Now, the this.viewCustomers the function will be only called once the db.customers.delete() function is completed and that should result in the desired output.
After some headche I've found a tricky solution that will give me the ability to update the table with the updated data. I've used the onClicked method of chrome.notifications API and now all works fine, but I'm opened to every suggestion about this problem.
Here is the code I've added in the mounted section of vue instance:
mounted() {
console.log('mounted')
this.$set(this, 'isActive', true)
this.viewCustomers()
browser.notifications.onClosed.addListener( (notificationId) => {
console.log(notificationId)
this.customersList = [];
this.viewCustomers();
})
}
I have a CZML datasource declared:
public geometryDataPromise: Cesium.CzmlDataSource;
I am loading it with an endpoint above when a component is loaded:
if(!this.store.geometryDataPromise) {
this.store.geometryDataPromise = Cesium.CzmlDataSource.load(environment.apiBaseURL + `/protectedareas/geometry/all`);
}
all the rendered objects are displayed to terrain but trying to follow the instructions by doing:
this.store.geometryDataPromise.show = false;
the objects are not being hidden
The problem here is that Cesium.CzmlDataSource.load does not return a Cesium.CzmlDataSource. It returns a Promise to asynchronously go get a CzmlDataSource, and that's not the same thing at all. Your code is trying to show or hide the promise, that's not a thing that gets displayed.
var dataSourcePromise = Cesium.CzmlDataSource.load( ... );
var dataSource = null;
dataSourcePromise.then(function(d) { dataSource = d; });
Note that after the above code runs, dataSource will be null for some time while the browser waits for the server's response to finish downloading. Once the callback function fires, the dataSource is ready.
function onClick() {
if (dataSource !== null) {
dataSource.show = !dataSource.show;
}
}
You can wire up a click handler for a toggle button like this. But the toggle won't do anything until after the dataSource is downloaded and ready.
First I have to take the result of the Cesium.CzmlDataSource.load promise
Cesium.when(Cesium.CzmlDataSource.load(environment.apiBaseURL + `/protectedareas/geometry/all`), result => {
this.sources = result;
this.viewer.dataSources.add(this.sources);
});
and then just change it's fiend show when the visibility changed
this.store.sourceVisibility.subscribe(visibility=>this.sources.show=visibility);
I'm building a custon social login page for my web application, and I'm stuck with a bug I can't find why it's hapenning .
Basically, I want to call a function called "connectFb" and then if all the Facebook API calls are successful, I would like to change a bunch of data in my vue instance in order to render other elements . (those are rendred conditionally via v-if)
Here's the part of my code responsible for this :
app = new Vue({
el : "#social-auth",
data: {
showTwitter : false,
showFb: true,
showPages: false,
fb_state: "unconnected",
continue_auth: false,
pages_fb: []
},
methods : {
connectFb: function() {
FB.login(function(response) {
if (response.authResponse) {
alert('You are logged in & cookie set!');
fb_token = response.authResponse.accessToken
FB.api('/me/accounts','get',{access_token: fb_token},function(pages){
if(pages["error"] !== undefined){
console.log('EROR')
}
else{
console.log("Got a list of pages");
console.log(pages);
this.pages_fb = pages.data;
this.showFb = false;
this.showPages = true;
this.continue_auth = true;
}
})
} else {
alert('User cancelled login or did not fully authorize.');
}
},{scope: 'public_profile,manage_pages'});
return false;
}
How The Code Works :
Basically, after the user is logged in to fb, it will get a list of his pages, this is not the problem, the problem is in the success callback after it (the callback related to the function fetching pages) . using the debugger I could see that the variable pages contains all the data I need and pages.data return an array of those pages info .
After this I'm trying to attribute it to my instance variable called pages_fb . when this code run pages_fb is always empty even though pages.data is not .
The problem is not only with pages_fb but also with all my instance variable that should change in the callback they are the same after the callback run .
I'm getting mad at this problem, so please help me understand what's wrong .
Extremely common mistake. this defined in your FB.login callback is not the Vue. Use an arrow function, closure, or bind to make it correct.
FB.api('/me/accounts','get',{access_token: fb_token}, pages => {
...
})
See How to access the correct this inside a callback?
When you use this. in a callback it isn't pointing to your Vue instance anymore. You can user => functions to bind this the way you want. Try this:
FB.api('/me/accounts','get',{access_token: fb_token},(pages) => {
if(pages["error"] !== undefined){
console.log('EROR')
}
else{
console.log("Got a list of pages");
console.log(pages);
this.pages_fb = pages.data;
this.showFb = false;
this.showPages = true;
this.continue_auth = true;
}
})
I am developing my app, and one of the features will be messaging within the application. What I did, is I've developed 'send message' window, where user can send message to other user. The logic behind it is as following:
1. User A sends message to User B.
2. Firebase creates following nodes in 'Messaging':
"Messaging"->"User A"->"User B"->"Date & Time"->"UserA: Message"
"Messaging"->"User B"->"User A"->"Date & Time"->"UserA: Message"
Here is the code that I am using for sending messages:
sendMsg: function(receiver, content) {
var user = Auth.getUser();
var sender = user.facebook.id;
var receiverId = receiver;
var receiverRef = $firebase(XXX.firebase.child("Messaging").child(receiverId).child(sender).child(Date()));
var senderRef = $firebase(XXX.firebase.child("Messaging").child(sender).child(receiverId).child(Date()));
receiverRef.$set(sender,content);
senderRef.$set(sender,content);
},
(picture 1 in imgur album)
At the moment, I am trying to read the messages from the database, and sort them in according to date. What I've accomplished so far, is that I have stored the content of "Messaging/UserA/" in form of an Object. The object could be seen in the picture I've attached (picture 2).
http://imgur.com/a/3zQ0o
Code for data receiving:
getMsgs: function () {
var user = Auth.getUser();
var userId = user.facebook.id;
var messagesPath = new Firebase("https://xxx.firebaseio.com/Messaging/");
var Messages = messagesPath.child(userId);
Messages.on("value", function (snapshot) {
var messagesObj = snapshot.val();
return messagesObj;
}, function (errorObject) {
console.log("Error code: " + errorObject.code);
});
}
My question is: how can I read the object's messages? I would like to sort the according to the date, get the message and get the Id of user who has sent the message.
Thank you so much!
You seem to be falling for the asynchronous loading trap when you're reading the messages:
getMsgs: function () {
var user = Auth.getUser();
var userId = user.facebook.id;
var messagesPath = new Firebase("https://xxx.firebaseio.com/Messaging/");
var Messages = messagesPath.child(userId);
Messages.on("value", function (snapshot) {
var messagesObj = snapshot.val();
return messagesObj;
}, function (errorObject) {
console.log("Error code: " + errorObject.code);
});
}
That return statement that you have in the Messages.on("value" callback doesn't return that value to anyone.
It's often a bit easier to see what is going on, if we split the callback off into a separate function:
onMessagesChanged(snapshot) {
// when we get here, either the messages have initially loaded
// OR there has been a change in the messages
console.log('Inside on-value listener');
var messagesObj = snapshot.val();
return messagesObj;
},
getMsgs: function () {
var user = Auth.getUser();
var userId = user.facebook.id;
var messagesPath = new Firebase("https://xxx.firebaseio.com/Messaging/");
var Messages = messagesPath.child(userId);
console.log('Before adding on-value listener');
Messages.on("value", onMessagesChanged);
console.log('After adding on-value listener');
}
If you run the snippet like this, you will see that the console logs:
Before adding on-value listener
After adding on-value listener
Inside on-value listener
This is probably not what you expected and is caused by the fact that Firebase has to retrieve the messages from its servers, which could potentially take a long time. Instead of making the user wait, the browser continues executing the code and calls your so-called callback function whenever the data is available.
In the case of Firebase your function may actually be called many times, whenever a users changes or adds a message. So the output more likely will be:
Before adding on-value listener
After adding on-value listener
Inside on-value listener
Inside on-value listener
Inside on-value listener
...
Because the callback function is triggered asynchronously, you cannot return a value to the original function from it. The simplest way to work around this problem is to perform the update of your screens inside the callback. So say you want to log the messages, you'd do:
onMessagesChanged(snapshot) {
// when we get here, either the messages have initially loaded
// OR there has been a change in the messages
console.log('Inside on-value listener');
var i = 0;
snapshot.forEach(function(messageSnapshot) {
console.log((i++)+': '+messageSnapshot.val());
});
},
Note that this problem is the same no matter what API you use to access Firebase. But the different libraries handle it in different ways. For example: AngularFire shields you from a lot of these complexities, by notifying AngularJS of the data changes for you when it gets back.
Also see: Asynchronous access to an array in Firebase
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.