Nativescript - Pass array from home-view-model to home.js - nativescript

I´m having a hard time understanding how to perform this action(as the title says), and maybe someone could help me understand the process, my code is below:
My home-view-model:
var Observable = require("data/observable").Observable;
var ObservableArray = require("data/observable-array").ObservableArray;
var http = require("http");
function createViewModel() {
http.getJSON("http://myJsonfile").then(function (r) {
var arrNoticias = new ObservableArray(r.data);
return arrNoticias;
}, function (e) {
});
}
exports.createViewModel = createViewModel;
I have done a console.log of the arrNoticias before i have putted it inside a callback function and it returns [object object] etc...and then i have done this:
console.log(arrNoticias.getItem(0).titulo);
and it returns the info i need!.
Then in my home.js file i have this:
var observableModule = require("data/observable")
var ObservableArray = require("data/observable-array").ObservableArray;
var arrNoticias = require('./home-view-model.js');
console.log(arrNoticias.getItem(0).titulo);
and the result in the console is:
TypeError: arrNoticias.getItem is not a function. (In 'arrNoticias.getItem(0)', 'arrNoticias.getItem' is undefined)
My question is, how does this action is perform? passing the data from view-model to the .js file?
Thanks for your time
Regards

As that function send a URL request so probably it's an async function, which is on hold while requesting so that's why you get undefined. Normally, you will want your function that sends a URL request to return a promise. Based on that promise, you will the result as expected after the request is done. So:
function createViewModel() {
return new Promise<>((resolve, reject) => {
http.getJSON("http://myJsonfile").then(function (r) {
var arrNoticias = new ObservableArray(r.data);
resolve(arrNoticias);
}, function(e) {
reject(e);
});
}), (e) => {
console.log(e);
})
}
In home.js:
var homeVM= require('./home-view-model.js');
var arrNoticias;
homeVM.createViewModel().then(function(r) {
arrNoticias = r;
});

Related

multiple Async/await JS function

In my controller, the fn function executes return.suucess() before my variables are properly defined. In this case, the ytb object.
The sails.log of "items" is correct, but "ytb" did not return.
I also tried with Promise.then, and .all. Also, with async.each() and removing the await inside this function.
fn: async function (inputs, exits) {
var url = require('url');
var items = await Collection.find({});
_.each(items, async item => {
if (item.youtube_url) {
var ytbUrl = item.youtube_url;
var regexBaseUrlYtb = new RegExp('(https://www.youtube.com/channel/)');
if (regexBaseUrlYtb.test(ytbUrl)) {
var ytbIdChannel = ytbUrl.replace(regexBaseUrlYtb, '');
var ytbChannel = await sails.helpers.youtubeApi(ytbIdChannel);
item.ytb = {};
Object.assign(item.ytb, ytbChannel);
}
}
sails.log('items: ', item)
});
return exits.success({
items
});
}
I expect that the ytb object will also be passed with the object item at the view, but the items object is passed without the ytb object.
Also, in general, I expect the return exits.success() runs only once the function finished
Thanks.

Jasmine spyOn function call inside function under test

I am trying to use Jasmine to test the following function:
var Pdba = Class.create();
Pdba.prototype = {
getChangeGroup: function(userId) {
var query = 'active=true^u_change_group=true^u_organization=false^';
var exGroup = new CompanyGroup();
var groups = exGroup.getGroupsByQuery(userId, query); //want to spy/mock this call
if (groups.next()) {
return groups.sys_id.toString();
}
return '';
}
type: 'Pdba'
};
I want to SpyOn the getGroupsByQuery() call, so that it doesn't make the actual call. Below is a collection of various things I have been trying, mostly just to see if I can "spy" and see that it has been called, then work on overriding so that I can replace the call with my own data.
describe('my suite of getChangeGroup tests', function() {
var expPdba;
var validUserId = 'user1';
var expGrp;
var ggbqMoc
beforeEach(function() {
expPdba = new global.Pdba();
coGrp = new CompanyGroup();
spyOn(coGrp, 'getGroupsByQuery');
ggbqMoc = jasmine.createSpy('getGroupsByQuery');
});
it('should return \'\' for empty userId', function() {
coPdba.getChangeGroup('');
expect(coGrp.getGroupsByQuery).toHaveBeenCalled();
expect(ggbqMoc).toHaveBeenCalled();
});
});
Is this possible or do I need to change the function under test to take a 'CompanyGroup' as a parameter?
Thank you
I'm assuming you are using jasmine v3. The syntax for creating a spy is pretty weird now- you have to pass a string that refers to the name of the variable you want to create a spy for, and then you pass an array of function names that should be spied on.
Try this:
describe('my suite of getChangeGroup tests', function() {
var expPdba;
var validUserId = 'user1';
var expGrp;
var spy;
beforeEach(function() {
expPdba = new global.Pdba();
coGrp = new CompanyGroup();
spy = jasmine.createSpyObj('coGrp', ['getGroupsByQuery'])
});
it('should return \'\' for empty userId', function() {
coPdba.getChangeGroup('');
expect(coGrp.getGroupsByQuery).toHaveBeenCalled();
expect(spy).toHaveBeenCalled();
});
});

fetch returning promise rather than value

Hopefully the code below communicates the problem clearly. The issue is that in the module which uses the get method of fetchData, the value being returned is the actual Promise, rather than the JSON as desired. Any thoughts on this?
// fetchData.js module
var _ = require('lodash');
function get() {
var endpoint1 = `/endpoint1`;
var endpoint2 = `/endpoint2`;
return fetch(endpoint1)
.then((endpoint1Response) => {
return endpoint1Response.json()
.then((endpoint1JSON) => {
return fetch(endpoint2)
.then((endpoint2Response) => {
return endpoint2Response.json()
.then((endpoint2JSON) => {
var data = _.merge({}, {json1: endpoint1JSON}, {json2: endpoint2JSON});
console.log('data in fetch', data); // this logs the json
return data;
});
});
});
});
}
exports.get = get;
// module which uses get method of fetchData get
var fetchData = require('fetchData');
var data = fetchData.get();
console.log('returned from fetchData', data); // this logs a Promise
Yes, that's exactly what's supposed to happen. The whole point of promises is that their result value is not immediately available and that doesn't change just because you're obtaining one from a separate module.
You can access the value like this:
var fetchData = require('fetchData');
fetchData.get().then(data =>
console.log('returned from fetchData', data);
);
Also note that you are using promises in a non-idiomatic way and creating a "tower of doom." This is much easier on the eyes and accomplishes the same thing:
function fetchJson(endpoint) {
return fetch(endpoint)
.then(endpointResponse => endpointResponse.json());
}
function get() {
var endpoint1 = `/endpoint1`;
var endpoint2 = `/endpoint2`;
return Promise.all([fetchJson(endpoint1), fetchJson(endpoint2)])
.then(responses => {
var data = { json1: responses[0], json2: responses[1] };
console.log('data in fetch', data); // this logs the json
return data;
});
}
Edit I haven't used async/await in JavaScript, but to answer your question, I presume this would work:
async function fetchJson(endpoint) {
var res = await fetch(endpoint);
return res.json();
}
async function get() {
var endpoint1 = `/endpoint1`;
var endpoint2 = `/endpoint2`;
var data = {
json1: await fetchJson(endpoint1),
json2: await fetchJson(endpoint2)
};
console.log('data in fetch', data); // this logs the json
return data;
}
// module which uses get method of fetchData get
async function main() {
var fetchData = require('fetchData');
var data = await fetchData.get();
console.log('returned from fetchData', data);
}
return main();

Knockout JS - update viewModel with AJAX Call

there are some similar questions but didn't help me to solve my issue. I can't update my results on page / view after updating my viewModel with AJAX. I am getting valid AJAX response that updates the view if I reload the page, but not when I click btnAdvancedSearch
I have simple HTML:
<div>
<input type="button" id="btnAdvancedSearch" data-bind="click: refresh" />
</div>
<div id="resultslist1" data-bind="template: { name: 'rest-template', foreach: restaurants }">
</div>
And I bind in on document load:
$(document).ready(function () {
ko.applyBindings(new RestaurantsListViewModel());
});
My viewModel is like this, and in it I call refresh that is bound with button
// Overall viewmodel for this screen, along with initial state
function RestaurantsListViewModel() {
var self = this;
self.restaurants = ko.observableArray([]);
var mappedRests = $.map($.parseJSON(sessionStorage.getItem('searchResults')), function (item) { return new Restaurant(item) });
self.restaurants = mappedRests;
self.refresh = function () {
updateRestaurantsList(); //Method executes AJAX and saves result to session.
var mappedRests2 = $.map($.parseJSON(sessionStorage.getItem('searchResults')), function (item) { return new Restaurant(item) });
self.restaurants= mappedRests2;
}
}
What am I missing here?
Thanks
I have tried waiting for AJAX to finish like this:
// Overall viewmodel for this screen, along with initial state
function RestaurantsListViewModel() {
var self = this;
self.restaurants = ko.observableArray([]);
var mappedRests = $.map($.parseJSON(sessionStorage.getItem('searchResults')), function (item) { return new Restaurant(item) });
self.restaurants = mappedRests;
self.refresh = function () {
var latitude = sessionStorage.getItem('latitude');
var longitude = sessionStorage.getItem('longitude');
var query = '{"Accepts_Reservations":"' + $('#chkReservation').is(":checked") + '","Accepts_Cards":' + $('#chkAcceptsCards').is(":checked") + '"}';
var searchResults = getRestaurantsAdvancedSearchAJAX(query, latitude, longitude, 40);
searchResults.success(function (data) {
var information = data.d;
var mappedRests2 = $.map($.parseJSON(information), function (item) { return new Restaurant(item) });
self.restaurants = mappedRests2;
});
};
};
Edit 1
Once you have declared your observable like so:
self.restaurants = ko.observableArray([]);
When you want to update restaurants you cannot do this:
self.restaurants = mappedRests2;
Instead, you need to do this:
self.restaurants(mappedRests2);
updateRestaurantsList(); //Method executes AJAX and saves result to session.
The comment after the above line indicates that this method is making an asynchronous call. Therefore, it is likely that the line after it is executing before sessionStorage has been populated. Maybe consider having updateRestaurantsList return a promise. Then you could update your code to something like this:
updateRestaurantsList().then(function() {
var mappedRests2 = $.map($.parseJSON(sessionStorage.getItem('searchResults')), function (item) { return new Restaurant(item) });
self.restaurants= mappedRests2;
});
This way the call to populate your mappedRests2 variable won't happen until after your updateRestaurantsList method has completed.
Edit 1
Be sure to never assign values to an observable using an equal sign.
// Overall viewmodel for this screen, along with initial state
function RestaurantsListViewModel() {
var self = this;
self.restaurants = ko.observableArray([]);
var mappedRests = $.map($.parseJSON(sessionStorage.getItem('searchResults')), function (item) { return new Restaurant(item) });
self.restaurants(mappedRests);
self.refresh = function () {
var latitude = sessionStorage.getItem('latitude');
var longitude = sessionStorage.getItem('longitude');
var query = '{"Accepts_Reservations":"' + $('#chkReservation').is(":checked") + '","Accepts_Cards":' + $('#chkAcceptsCards').is(":checked") + '"}';
var searchResults = getRestaurantsAdvancedSearchAJAX(query, latitude, longitude, 40);
searchResults.success(function (data) {
var information = data.d;
var mappedRests2 = $.map($.parseJSON(information), function (item) { return new Restaurant(item) });
self.restaurants(mappedRests2);
});
};
};

Node JS - get file via AJAX and then use the data

How do I do this asynchronously?
var getData, myFunc;
getData = function() {
var data = "";
$.get("http://somewhere.com/data.xml", function(d) {
data = $("#selector", d).html();
});
return data; // does not work, because async callback not yet fired
};
myFunc = function() {
var data = getData();
// do something with data here
};
I am happy to completely re-factor to achieve what I want. I am just don't know what design pattern achieves this.
Well, you can't. You can return a promise though:
var getData, myFunc;
getData = function () {
var d = $.Deferred();
$.get("http://somewhere.com/data.xml", function (data) {
d.resolve($("#selector", data).html())
});
return d.promise();
};
getData().then(function (data) {
alert(data);
});
demo http://jsfiddle.net/W75Kt/2/

Resources