I'm just having a play with Vue.js (pretty new to javascript too) and trying to access the events in my Google calendar.
I keep getting 'undefined' when looking in the console.
new Vue({
el: '#app',
data: {
client_id: 'my_client_id',
scopes: ["https://www.googleapis.com/auth/calendar.readonly"],
events: {
title: 'Upcoming Events',
items: [],
}
},
created: function () {
this.loadCalendarApi();
},
methods: {
addEvent: function (event) {
this.events.items.push({
title: event.summary,
date: event.start.dateTime
});
},
loadCalendarApi: function () {
gapi.client.load('calendar', 'v3', this.listUpcomingEvents);
},
listUpcomingEvents: function () {
var request = gapi.client.calendar.events.list({
'calendarId': 'primary',
'timeMin': (new Date()).toISOString(),
'showDeleted': false,
'singleEvents': true,
'maxResults': 10,
'orderBy': 'startTime'
});
var events = this.requestEvents(request);
console.log(events);
},
requestEvents: function (request) {
return request.execute(function (resp) {
resp.items;
});
},
},
});
I think the offending code is somewhere in the requestEvents method.
I also know that 'this.addEvent' is not in scope to be able to refer to the Vue object from inside the request.execute function but I don't know what I need to change.
Can anyone help me or let me know what I'm doing wrong?
Thanks!
Two ways you could do it, one would be to change execute(function) to execute(function, vue) and pass this in as the second argument. Then you could access it like so:
//update your execute function to pass along the vue variable into the response, then
requestEvents: function (request) {
var events = request.execute(function (resp, vue) {
for (i = 0; i < resp.items.length; i++) {
vue.addEvent(resp.items[i]);
}
}, this);
return events;
}
Or if you have jQuery available, you can take a look at $.proxy() which alters a function to use the current context: https://api.jquery.com/jQuery.proxy/
requestEvents: function (request) {
var events = request.execute($.proxy(function (resp) {
for (i = 0; i < resp.items.length; i++) {
this.addEvent(resp.items[i]);
}
}, this));
return events;
}
This way the anonymous response function will be run in the context of your Vue object.
Edit: I found this page as well which shows how you can bind the current context to a function using native JS, jQuery, or Underscore. Any of these would work: https://jsperf.com/bind-vs-jquery-proxy/5
Nowadays you could use the request => {} notation instead of function(request) {} notation, which will pass on the context to the executing method so this.AddEvent() will work as expected.
Related
I am using updatingAll method in loopback but it is not working I am not able to understand the reason
I have written something like this
let data = {
isActive: false
};
myModel
.updateAll(data, {
id: {
inq: questionIds
},
});
The order of parameters in updateAll seems to be incorrect. From documentation:
PersistedModel.updateAll([where], data, callback)
Also, it seems a callback function is required.
Callback function called with (err, info) arguments. Required.
So your call should look like this:
let data = {
isActive: false
};
myModel.updateAll({
id: {
inq: questionIds
},
}, data, (err, info) => null); //might want to add error checking to callback function
I need to figure out how to call this function synchronously.
fetchData: function(recs){
store = Ext.getStore('OutOfBalanceList');
store.reload({
params: {
startDate: searchForm.startDate,
endDate: searchForm.endDate,
cusip: searchForm.cusip,
account: searchForm.account
},
callback: function (records, options, success) {
recs = records.length;
return recs;
}
});
},
I appreciate all the sermons about Async, but in this case I have to use Synchronous calls because when the data returned is empty, I have to call back again with different parameters. Presently this ends up being an infinite loop because "recs" is not changed outside!
Many thanks
Don't try and make it synchronous. Do the "call again with different parameters" inside your callback method. Something like this:
fetchData: function(recs) {
var me = this;
store = Ext.getStore('OutOfBalanceList');
store.reload({
params: {
startDate: searchForm.startDate,
endDate: searchForm.endDate,
cusip: searchForm.cusip,
account: searchForm.account
},
callback: function (records, options, success) {
if (records.length == 0) {
me.fetchDataWithDifferentParameters();
}
}
});
}
If you're going to work with JavaScript frameworks and calls to external data sources, then learning how to use callbacks is pretty darn important.
I have a .NET webservice that returns an object like:
myObj = {
prop1: value,
prop2:value,
...
prop5:value
}
I created an angular service that returns this entire object(myObj).
I created 5 distinct directives to display these properties in different pages in the application(sometimes, some of them can be in the same page).
I'm calling the angular service in these directives, creating for any of them this "link" function:
link: function (scope, element, attrs) {
getService.getMethod().$promise.then(
function (myObj) {
element.text(myObj.prop1); // .prop2, ... , prop5
},
function (statusCode) {
console.log(statusCode);
}
);
}
I have the feeling that my approach is not the best, calling five times the angular service(through the $promise) obtaining actually the same object(myObj).
If you are interested also how the service is looking:
var localResource = $resource('https://.....',
{},
{'getAll': {method: 'JSONP', isArray: false, params: {callback: 'JSON_CALLBACK'}}}
);
return {
getMethod: function () {
return localResource.getAll();
}
}
Please help, if someone has an ideea haw can I improve it.
Thank you!
It sounds like you can make your getMethod issue only one server call.
.factory("getService", function () {
var getAll;
return {
getMethod: function () {
if (!getAll) {
getAll = localResource.getAll();
}
return getAll;
};
};
});
Maybe I am not understanding scoping but in the following:
AisisWriter.Routers.Posts = Backbone.Router.extend({
writer_posts: null,
posts: null,
routes : {
'': 'index'
},
initialize: function() {
this.writer_posts = new AisisWriter.Collections.Posts();
},
index: function() {
var self = this;
this.writer_posts.fetch({
reset: true,
success: function(collection, response, options){
this.posts = collection;
console.log(this.posts);
}
});
console.log(self.posts)
}
});
inside the success: function(){} the this.posts console log has two posts in it. it looks like:
child {length: 1, models: Array[1], _byId: Object, constructor: function, model: function…}
But when I try and use this.posts out side the fetch call, it returns null. Why is that? Is this not scoped properly? or am I doing something wrong?
You are not being able to get access to your this.posts only because it is executed sooner than you get the response. You even don't have to save 'this' in the self variable. To check it just add in the initialize function this line:
this.listenTo(this.writer_posts, 'reset', this.test);
And then create test function:
test: function() { console.log(this.posts); }
As you will see collection is saved properly.
Since your fetch might take time to get into success promise the next line is getting executed sooner before that.
index: function() {
var self = this;
this.writer_posts.fetch({
reset: true,
success: function(collection, response, options){
//write your callback function inside the success
//self.afterSuccess(collection);
}
});
},
You can pass the parameters for the function and fetch it.
afterSuccess: function(collection) {
console.log("the collection has"+JSON.stringify(collection));
}
I have some global parameters that I want to be sent in every time I call a fetch on a collection... my issue is I don't want to declare the data: { ... } every time I fetch.
Is there a way I can provide default parameters inside the Collection itself with the possibility to add more or override some?
For example:
Instead of doing this every time:
this.articlesCollection.fetch({
dataType: 'jsonp',
data: {
deviceType: GlobalVars.deviceType,
memberId: GlobalVars.memberId,
authToken: GlobalVars.authToken,
targetObjectId: userId,
limit: 50,
excludeArticleBodies: true,
excludeViewedItems: false
},
success: function() {
_this.render();
}
});
I'd like to just provide a one or two parameters and a success function, like this:
this.articlesCollection.fetch({
data: {
targetObjectId: userId
},
success: function() {
_this.render();
}
});
... and have the Collection look something like:
define([
'underscore',
'backbone',
'global',
'utilities',
'models/article/ArticleModel'
], function(_, Backbone, GlobalVars, Utils, ArticleModel){
var ArticlesCollection = Backbone.Collection.extend({
model: ArticleModel,
initialize : function(view) {
this.view = view;
},
dataType: 'jsonp',
data: {
deviceType: GlobalVars.deviceType,
memberId: GlobalVars.memberId,
authToken: GlobalVars.authToken,
limit: 50,
excludeArticleBodies: true,
excludeViewedItems: false
},
url : function() {
return GlobalVars.baseAPIUrl + '/API/GetArticles';
},
parse : function(data) {
return data.Articles;
}
});
return ArticlesCollection;
});
Here's a working jsFiddle with one approach: http://jsfiddle.net/LEuGq/1/
Basically, you configure both an object of defaultParams and params as properties of your collection, which are used to dynamically compute the correct URL when fetch() is called. This way is probably more in alignment with backbone than changing the API of fetch() to accept parameters, which it is not designed to do.
var ParamCollection = Backbone.Collection.extend({
defaultParams: {deviceType: 'raceCar', limit: 42},
params: {},
url: function() {
return "/paramcollection?" + $.param(_.defaults(this.params, this.defaultParams));
}
});
var paramCollection = new ParamCollection();
paramCollection.params.excludeArticleBodies = true;
paramCollection.params.limit = 52;
$("#debug").append(paramCollection.url());
Backbone uses jQuery's ajax call by default, so you can set up anything you need as a default using various methods. See this question for some examples: jQuery's ajaxSetup - I would like to add default data for GET requests only