Return Ajax Data within Object - javascript

I am having an issue getting an Ajax Response to be used within an Object.
function cart(){
this.items = [];
this.addItem = function(item){
//sorts and adds items to this.items
}
this.retrieveCart = function(){
var itemArray = JSON.parse($.cookie('cartItems'));
var itemNumbers = [];
var outData = [];
for(var i in itemArray){
itemNumbers.push(i);
}
$.post('beta-category-ajax.html', {'get' : itemNumbers.join(",")},
function(data){
for(var i in data){
var currentItemNumber = data[i].I;
var quantity = itemArray[currentItemNumber];
data[i].Quantity = quantity;
outData.push(data[i]);
}
});
this.addItem(outData);
}
I want to be able to run the this.addItem(Array) while still using Ajax asynchronously
I saw this thread jQuery AJAX Handling Problem but I am not if this applies to me.
Thank you all for the help ahead of time :)

I'm not entirely clear on what you are asking, but it appears that this.addItem wouldn't work the way the code is currently written. The value of this changes in the scope of the anonymous function you're passing to $.post. Cache a reference to this in retrieveCart.
this.retrieveCart = function () {
var self = this;
...
$.post(..., function () {
...
self.addItem(outData);
});
}

Related

javascript class with event methods

My goal is to make a class with some chained functions, but I'm stuck and hoping for some help. This is what I got:
robin = new batman("myiv");
var batman = (function() {
var me = this;
function batman(id){
me._id=id;
document.getElementById(id).addEventListener('mousemove', me.mouseMoving.bind(me),true);
}
this.mouseMoving = function(){
document.getElementById(me._id).style.background="orange";
}
return batman;
}
And this pseudo code is what I am aiming to get. Basically, pass in the ID of an element in my HTML and chain functions to it such as onclick etc, and whatever code inside there, runs. as in example, changing background colors.
Is it possible?
superman("mydiv"){
.onmouseover(){
document.getElementById(the_id).style.background="#ffffff";
},
.onmouseout(){
document.getElementById(the_id).style.background="#000000";
},
etc...
}
edit: updated with missing code: "return batman;"
You can do method chaining by returning the current object using this keyword
var YourClass = function () {
this.items = [];
this.push = function (item) {
if (arguments) {
this.items.push(item);
}
return this;
}
this.count = function () {
return this.items.length;
}
}
var obj = new YourClass();
obj.push(1).push(1);
console.log(obj.count())
Working sample
https://stackblitz.com/edit/method-chaining-example?file=index.js

KnockoutJS: Show message when the returned array is empty

I'd like to show a message in case the returned array of tasks is empty. I used this:
<span data-bind="visible: tasksArr().length == 0">
There are no tasks yet.
</span>
But it doesn't work properly. When I load the page, the message shows up for a second before the content is loaded into the array because tasksArr is declared before the request is finished fetching the content. Is there an easier way to have it show up after the load is completed without resorting to an extra observable?
As you can see in this fiddle the default value of an obervableArray is an empty array.
So there no difference between an uninitialized obervableArray and an empty obervableArray.
There are 2 work arrounds :
Declaring more observables :
function vm() {
var self = this;
self.tasksArr = ko.observableArray([]);
self.initilized = ko.observable(false);
self.canSee = ko.computed(function(){
var a = self.tasksArr().length;
return self.initilized() && a;
});
self.load = function () {
setTimeout(function () {
for (var i = 0; i < 100; i++) {
self.tasksArr.push(i);
}
self.initilized(true);
}, 1000);
}();
}
ko.applyBindings(new vm());
See fiddle
You can also delay the binding
function vm() {
var self = this;
self.tasksArr = ko.observableArray();
self.load = function () {
setTimeout(function () {
/*for (var i = 0; i < 100; i++) {
self.tasksArr.push(i);
}*/
ko.applyBindings(x);
}, 1000);
}();
}
var x = new vm();
See fiddle
I hope it helps.
hide the span by default (display:none;). This way, the Message will be hidden on page load and only become visible when tasksArr is indeed empty.

AngularJS/ JS How do I access variables outside my function?

I'm trying to access the variable np defined from within a function block; however, I am running into some issues when I call this.items.push(plumbers). I get TypeError: Cannot call method push of undefined
myApp.factory('np', function($resource, nearbyPlumbers){
var np = function(){
this.items = [];
this.busy = false;
this.limit = 5;
this.offset = 0;
};
np.prototype.nextPage = function(){
if (this.busy) return;
this.busy = true;
var temp;
nearbyPlumbers.nearby({lat: -37.746129599999996, lng: 144.9119861}, function(data){
angular.forEach(data, function(plumber){
alert('yay');
//this.items.push(plumber);
console.log(plumber);
console.log(this.items); // <--- This wont work. How do I access this.items
});
});
};
return np;
});
np.prototype.nextPage = function () {
if (this.busy) return;
this.busy = true;
var temp;
var that = this; // add this line
nearbyPlumbers.nearby({
lat: -37.746129599999996,
lng: 144.9119861
}, function (data) {
angular.forEach(data, function (plumber) {
that.items.push(plumber); //access using "that"
console.log(plumber);
console.log(that.items);
});
});
};
I'm really curious why you're using this, since it's going to be a different this depending on what scope accessing the singleton from. That would explain the error that you're getting.
I would strongly suggest reading up on factories in Angular and then taking another look at the code. The services docs are a good place to start and this question is good as well.

Knockout.js: Using nested observables with mapping plugin

I am building a sidebar to filter a main view, like for instance the one at John Lewis. I have the code working but it ain't pretty.
I know there are several SO questions on similar lines but I can't quite fathom my own use case.
I need to get the names of the checkboxes from the server ( eg via JSON ) to dynamically create observableArrays on my ShopView.
Here's how it is:
var data = {
'gender' : [ ],
'color' : [ ]
};
var filterMapping = {
create: function( obj ) {
return ko.observableArray( obj.data );
}
}
var ShopView = new function() {
var self = this;
ko.mapping.fromJS( { filters: data }, filterMapping, self );
// this is the bit I don't like
this.filterChange = ko.computed(function () {
for( var key in self.filters ) {
var obj = self.filters[key];
if( ko.isObservable(obj)){
obj();
}
}
});
this.filterChange.subscribe( function( ) {
//make AJAX request for products using filter state
});
}
My HTML looks as you'd expect:
Gender
<ul>
<li><input type="checkbox" value="male" data-bind="checked: filters.gender" />Male</li>
<li><input type="checkbox" value="female" data-bind="checked: filters.gender" />Female</li>
</ul>
As I say, it works, but it's not nice. In an ideal world I could subscribe to this.filters, eg
this.filters.subscribe( function() {
//make AJAX request for products using filter state
});
NB I'm not trying to do the filtering on the client side - just update my viewmodel when the dynamically-bound checkboxes change.
Any ideas? thanks!
First, the mapping plugin should be treated as an aid to code duplication. I don't think its a good idea to think of the mapping plugin as a solution in and of itself; at least not directly. It also obscures what is happening when you post your code on SO, since we can't see the models you are working with. Just a thought.
Now, ff you want to get dynamic filters from the server, and use them to filter a list of items (like you would in a store), I would do it something like this (here is the fiddle):
var FilterOption = function(name) {
this.name = name;
this.value = ko.observable(false);
};
var Filter = function(data) {
var self = this;
self.name = data.name;
options = ko.utils.arrayMap(data.options, function(o) {
return new FilterOption(o);
});
self.options = ko.observableArray(options);
self.filteredOptions = ko.computed(function() {
var options = []
ko.utils.arrayForEach(self.options(), function(o) {
if (o.value()) options.push(o.name);
});
//If no options, false represents no filtering for this type
return options.length ? options : false;
});
};
var ViewModel = function(data) {
var self = this;
self.items = ko.observableArray(data.items);
filters = ko.utils.arrayMap(data.filters, function(i) {
return new Filter(i);
});
self.filters = ko.observableArray(filters);
self.filteredItems = ko.computed(function() {
//Get the filters that are actually active
var filters = ko.utils.arrayFilter(self.filters(), function(o) {
return o.filteredOptions();
});
//Remove items that don't pass all active filter
return ko.utils.arrayFilter(self.items(), function(item) {
var result = true;
ko.utils.arrayForEach(filters, function(filter) {
var val = item[filter.name.toLowerCase()];
result = filter.filteredOptions().indexOf(val) > -1;
});
return result;
});
});
};
The next obvious step would be to add support for items that had multiple properties, but or options properties, but this should give you the basic idea. You have a list of filters, each with any number of options (which stack additively), and you use a computed items array to store the result of filtering the items.
Edit: To get the items using an ajax subscription, you would replace the FilteredItems prop with a computed that gets the selected filters, and then subscribe to it, like this:
var ViewModel = function(data) {
var self = this;
self.items = ko.observableArray(data.items);
filters = ko.utils.arrayMap(data.filters, function(i) {
return new Filter(i);
});
self.filters = ko.observableArray(filters);
self.selectedFilters = ko.computed(function() {
ko.utils.arrayFilter(self.filters(), function(o) {
return o.filteredOptions();
});
});
self.selectedFilters.subscribe(function() {
//Ajax request that updates self.items()
});
};

How can I pass results from a callback via an object?

I am performing a Google local search, and wish to return the lat/long via an object.
The Google search itself works fine.
When inspected (using console.log or alert()) in the object itself, the results field appears to be populated OK.
However, when inspecting the instance of the object (instantiated before running the callback) the result is blank. I'm aware I don't need the accessor function - the end result is the same either way.
Is there something fundamental missing here? Thanks!
function GeoSearch() {
this.results = [];
this.searchComplete = function(localSearch) {
if(localSearch.results[0]) {
var resultLat = localSearch.results[0].lat;
var resultLng = localSearch.results[0].lng;
this.results = localSearch.results[0].lat;
}
}
this.getResults = function() {
return this.results;
}
}
function populateCoords(postcode) {
var localSearch = new google.search.LocalSearch();
var gs = new GeoSearch();
localSearch.setSearchCompleteCallback(gs, gs.searchComplete, [localSearch]);
localSearch.execute(postcode + ", UK");
alert(gs.getResults());
}
When you reference the function gs.searchComplete, you're detaching the method from the object it belongs to. Switch it to function () { gs.searchComplete(); }

Categories

Resources