Return value from angularjs factory - angularjs

I try to set up this example https://github.com/AngularClass/angular-websocket#usage
Here is my code
App.factory('MyData', function($websocket, $q) {
var dataStream = $websocket('wss://url');
var collection = [];
dataStream.onMessage(function(message) {
var result = JSON.parse(message.data);
console.log(result);
collection = result;
});
var methods = {
collection: collection,
get: function() {
dataStream.send(JSON.stringify({
api: "volume",
date: "2017-02-01",
interval: 600
}));
}
};
return methods; });
In my controller I wrote:
$interval(function () {
console.log(MyData.collection);
}, 1000);
The problem is that I don't receive any values, however on message arrive I see console log, so websocket itself is obviously alive. If I change collection.push(result) (like in example) I receive constantly growing array. I need only the last value, however. Why collection = result is wrong ?

var collection = []; instantiates a new array and its reference is stored in the variable collection. Then, this reference is assigned to methods.collection and, hence, MyData.collection. However, with JSON.parse a new array is instantiated. collection = result; overwrites the original reference with the reference of the new array. But MyData.collection still holds the reference to original array.
So, there are two ways to encounter the problem:
Don't overwrite the reference to the original array. push is good, but before, you need to clear the array in order to only show the last value.
collection.splice(0, collection.length);
collection.push(result);
However, that would be an array in an array. You probably need to push the values individually (Array.concat will create a new array, too):
collection.splice(0, collection.length);
result.forEach(function(value) {
collection.push(value);
});
Assign the reference of the new array directly to methods.collection. In this case, no extra variable collection is needed.
App.factory('MyData', function($websocket, $q) {
var dataStream = $websocket('wss://url');
var methods = {
collection: [],
get: function() {
dataStream.send(JSON.stringify({
api: "volume",
date: "2017-02-01",
interval: 600
}));
}
};
dataStream.onMessage(function(message) {
var result = JSON.parse(message.data);
console.log(result);
methods.collection = result;
});
return methods;
});

Related

AngularJS is setting value for unrelated scope variable

I have the following angular code to initialize an angular form. It returns a mostly null record except for a couple of dates and employee info.
I was trying to create a scope variable to keep the original record for comparison purposes after the form is filled out. This is what $scope.TechSheetInfoStatic is for.
For our purposes here, I set $scope.TechSheetInfo.Customer.Email to a dummy value. This, while updating $scope.TechSheetInfo, also updates $scope.TechSheetInfoStatic. Why?
$scope.initializeTechSheet = function() {
$scope.TechSheetInfo = [];
$scope.TechSheetInfoStatic = [];
$scope.customerIDDisabled = false;
$scope.orderIDDisabled = false;
const successFunction = function(response) {
$scope.TechSheetInfo = response.data;
$rootScope.customerInfo = response.data.Customer;
$scope.TechSheetInfoStatic = response.data;
$scope.TechSheetInfo.Customer.Email = "bobo#bobo.com";
alert(JSON.stringify($scope.TechSheetInfo.Customer));
alert(JSON.stringify($scope.TechSheetInfoStatic.Customer));
};
const failureFunction = function(response) {
//console.log('Error' + response.status);
};
TechSheetFactory.ITS(successFunction, failureFunction);
};
Use angular.copy to make a deep copy:
const successFunction = function(response) {
$scope.TechSheetInfo = response.data;
$rootScope.customerInfo = response.data.Customer;
̶$̶s̶c̶o̶p̶e̶.̶T̶e̶c̶h̶S̶h̶e̶e̶t̶I̶n̶f̶o̶S̶t̶a̶t̶i̶c̶ ̶=̶ ̶r̶e̶s̶p̶o̶n̶s̶e̶.̶d̶a̶t̶a̶;̶
$scope.TechSheetInfoStatic = angular.copy(response.data);
$scope.TechSheetInfo.Customer.Email = "bobo#bobo.com";
alert(JSON.stringify($scope.TechSheetInfo.Customer));
alert(JSON.stringify($scope.TechSheetInfoStatic.Customer));
};
Since response.data is an object. The assignment statement assigns a reference value to the variable. The angular.copy function will create a new object and copy the contents to the new object.
A variable holding an object does not "directly" hold an object. What it holds is a reference to an object. When you assign that reference from one variable to another, you're making a copy of that reference. Now both variables hold a reference to an object. Modifying the object through that reference changes it for both variables holding a reference to that object.
For more information, see Pass-by-reference JavaScript objects.

Extending $firebaseArray with an extended $firebaseObject

Trying to cut down code repetition, I've set up a $firebaseArray extension as follows:
var listUsersFactory = $firebaseArray.$extend({
$$added: function (snap) {
return new Customer(snap);
},
$$updated: function (snap) {
var c = this.$getRecord(snap.key);
var updated = c.updated(snap);
return updated;
},
});
and the Customer code:
function Customer(snap) {
this.$id = snap.key;
this.updated(snap);
}
Customer.prototype = {
updated: function(snap) {
var oldData = angular.extend({}, this.data);
this.data = snap.val();
// checks and such
}
}
This works wonders when loading, showing and saving a list of customers, and I'm satisfied with it.
Now, the problem lies in retrieving a single customer and its detail page, because the Customer object isn't an extension of $fireObject and is therefore lacking a $save method
Single customer loading:
customersRef.once("value", function(snapshot) {
if(snapshot.child(uuid).exists())
{
customersFactory.customerDetails = new Customer(snapshot.child(uuid));
return deferred.resolve();
}
}
but when I call customersFactory.customerDetails.$save() I get an error
How can I extend my class so that it works for both array and single object uses?
I couldn't find a way to do this, so I ended up using the $firebaseArray and getting single records off that to pass as details, in case anyone's wondering

angularjs 2way binding between service and controller with an array

Before I start, I will link my codepen so you can have a look before reading this :)
I have made a very simple app to demonstrate my issue.
basically when I have multiple services sharing an array, it appears that angularjs treats the array as a primitive object which is odd.
I have to link code, so this is my controller and 2 services at the start:
angular.module('bindingApp', [])
.controller('MainController', ['MainService', 'SelectionsService', function (service, selections) {
// Map the controller to a variable
var self = this;
// Attach the model to our scope
self.models = service.models;
// Create a function that handles the changes the service in some way
self.updateSelectedItems = function () {
// Get our first item
var models = selections.selected;
// Loop through our selected items
for(var i = 0; i < models.length; i++) {
// Get our current model
var model = models[i];
// Change the properties
model.status = 'Cancelled';
model.colour = 'gray';
}
};
// Reset everything
self.reset = function () {
selections.reset();
service.reset();
console.log('models in the controller', self.models);
}
// Map our function to our service function
self.selectItem = selections.select;
// Initialize our service
service.init();
}])
.service('MainService', function () {
// Create our service
var service = {
// Create the default model (empty array)
models: [],
// Populates our model
init: function () {
// Loop from 1 to 10
for(var i = 0; i < 10; i++){
// Create some object
var model = {
status: 'Live',
colour: 'green',
selected: false
};
// Push our model to our array
service.models.push(model);
}
console.log('models in the service', service.models);
},
// Resets everything
reset: function () {
// Reset our array
service.models = [];
// Initialize
service.init();
}
};
// Return our service
return service;
})
.service('SelectionsService', function () {
// Create our service
var service = {
// Create a reference to our selected objects
selected: [],
// Our select function
select: function (e, item) {
// Create a reference to our selected items
var selected = service.selected;
// Update the selected status
item.selected = true;
// Push our item to our selected items
selected.push(item);
// Stop propagation
e.stopPropagation();
e.preventDefault();
},
// Resets our selected items
reset: function () {
service.selected = [];
}
};
// Return our service
return service;
});
I have created 2 more Codepens to try to fix the issue. The first one maps the items to an object encapsulating an array in the MainController. The second one does the same, but also the MainService has an object encapsulating the array.
Does anyone know what I can do to get this simple pen working?
OK. This doesn't have much to do with Angular. Just plain JavaScript.
Here's what happens:
The service initializes its models array. service.models is a variable that contains a reference to that array. You thus have
service.models ----> [firstArray]
Then the controller does self.models = service.models;. So it creates another reference pointing to the same array, referenced by service.models:
service.models ----> [firstArray]
^
controller.models ----|
Then you click the reset button, which calls service.reset(), which does service.models = [];. So it creates a new array and assigns it to its models variable. You thus end up with
service.models ----> []
controller.models --> [firstArray]
Note that you never make controller.models point to the new array in the service. So it still points to the first array, and the view still displays the elements of that first array.
So, either you make sure to reinitialize the controller's models variable after calling reset():
controller.models = service.models;
Or you make sure to simply remove everything from the original, first array in reset():
service.models.splice(0, service.models.length)
It looks like that you must not reset the models array by referencing a new empty array but removing all items from it.
Instead
// Reset our array
service.models = [];
use
// Reset our array
service.models.length = 0;

Add variable to an existing json object

request = myService.getCases();
request.then(
function(payload) {
$scope.cases = payload.data;
var time = Math.floor((Date.now() - Date.parse($scope.cases[i].date_case_modified))/(60000*60*24));
$scope.cases.duration.push(time);
}
});
Inside the controller I am trying to tack on the cases.duration onto the cases object but it wont add it onto the object that is returned. Any ideas?
I think you just need to introduce a forEach as shown here:
request = myService.getCases();
request.then(
function(payload) {
$scope.cases = payload.data;
angular.forEach($scope.cases, function (el) {
var time = Math.floor((Date.now() - Date.parse(el.date_case_modified))/(60000*60*24));
el.duration = time;
});
}
});
Hope this helps

passing data to a collection in backbone

So I am trying storing product types from a json file before trying to add them to a collection but am getting some strange results (as in I dont fully understand)
on my router page i setup a variable for cached products as well as product types
cachedProductTypes: null,
productType : {},
products : {},
getProductTypes:
function(callback)
{
if (this.cachedProductTypes !== null) {
return callback(cachedProductTypes);
}
var self = this;
$.getJSON('data/product.json',
function(data)
{
self.cachedProductTypes = data;
callback(data);
}
);
},
parseResponse : function(data) {
result = { prodTypes: [], products: [] };
var type;
var types = data.data.productTypeList;
var product;
var i = types.length;
while (type = types[--i]) {
result.prodTypes.push({
id: type.id,
name: type.name,
longName: type.longName
// etc.
});
while (product = type.productList.pop()) {
product.productTypeId = type.id,
result.products.push(product);
}
};
this.productType = result.prodTypes;
console.log( "dan");
this.products = result.products;
},
showProductTypes:function(){
var self = this;
this.getProductTypes(
function(data)
{
self.parseResponse(data);
var productTypesArray = self.productType;
var productList=new ProductsType(productTypesArray);
var productListView=new ProductListView({collection:productList});
productListView.bind('renderCompleted:ProductsType',self.changePage,self);
productListView.update();
}
);
}
when a user goes to the show product types page it runs the showProductsType function
So I am passing the products type array to my collection
on the collection page
var ProductsType=Backbone.Collection.extend({
model:ProductType,
fetch:function(){
var self=this;
var tmpItem;
//fetch the data using ajax
$.each(this.productTypesArray, function(i,prodType){
tmpItem=new ProductType({id:prodType.id, name:prodType.name, longName:prodType.longName});
console.log(prodType.name);
self.add(tmpItem);
});
self.trigger("fetchCompleted:ProductsType");
}
});
return ProductsType;
now this doesnt work as it this.productTypesArray is undefined if i console.log it.
(how am I supposed to get this?)
I would have thought I need to go through and add each new ProductType.
the strange bit - if I just have the code
var ProductsType=Backbone.Collection.extend({
model:ProductType,
fetch:function(){
var self=this;
var tmpItem;
//fetch the data using ajax
self.trigger("fetchCompleted:ProductsType");
}
});
return ProductsType;
it actually adds the products to the collection? I guess this means I can just pass an array to the collection and do not have to add each productType?
I guess this means I can just pass an array to the collection and do not have to add each productType?
Yes, you can pass an array to the collection's constructor, and it will create the models for you.
As far as your caching code, it looks like the problem is here:
if (this.cachedProductTypes !== null) {
return callback(cachedProductTypes);
}
The callback statement's argument is missing this - should be return callback(this.cachedProductTypes).

Resources