Cannot read property 'push' of undefined from Angular push - json

I'm trying to push attributes to a json file and I'm getting an error...
TypeError: Cannot read property 'push' of undefined
This is my controller....
'use strict';
(function () {
var userQuoteBuild = angular.module('priceQuoteApp');
userQuoteBuild.controller('quoteBuilderController', function ($scope, $http, $timeout, productsServices, userQuoteBuild) {
$scope.getProductDetails = function (item) {
userQuoteBuild.setProductName(item.product_name)
userQuoteBuild.SelectedProductattributes1.push({
bearerBandwidth: '100',
description: 'item2'
});
};
});
userQuoteBuild.controller('productDisplayer', function ($scope, userQuoteBuild) {
$scope.userQuoteBuild = userQuoteBuild;
$scope.$watch(function () { return userQuoteBuild.getProductName(); }, function (newValue) {
if (newValue) $scope.selected_product_name = newValue;
});
});
}());
and this is where I am keeping the json....
var userQuoteBuild = angular.module('priceQuoteApp');
userQuoteBuild.factory('userQuoteBuild', function () {
var SelectedProductattributes1 = [{
bearerBandwidth: '',
description: ''
}];
});
Can anyone see what I am doing wrong? Thanks

Edit: I just noticed that your app variable is the same as your factory variable. You should fix that too.
eg var app = angular.module('priceQuoteApp'); then app.factory( ....
Your factory needs to return the variable to be able to access the contents
app.factory('userQuoteBuild', function () {
return [{
bearerBandwidth: '',
description: ''
}];
});
Then to append simply
userQuoteBuild.push({ ... });
or, if you want to give yourself some more room in your factory
app.factory('userQuoteBuild', function () {
return {
SelectedProductattributes1: [{
bearerBandwidth: '',
description: ''
}]
};
});
then
userQuoteBuild.SelectedProductattributes1.push({ ... });

Related

AngularJS : Factory JSON Array with HTTP GET

I'm developing my first AngularJS app using the Google Docs API to pass it JSON data.
This is an example of the factory I'm using:
app.factory('Data', ['$http', 'apiKeys', function($http, apiKeys){
var googleDocs = 'https://spreadsheets.google.com/feeds/list/';
return {
news:function () {
return $http.get(googleDocs + apiKeys.googleDoc +'/1/public/values?alt=json', {cache: true});
},
updates:function () {
return $http.get(googleDocs + apiKeys.googleDoc +'/2/public/values?alt=json', {cache: true});
},
docs:function () {
return $http.get(googleDocs + apiKeys.googleDoc +'/3/public/values?alt=json', {cache: true});
}
}]);
I wanted to clean up a bit the code and decided to use services instead of making the calls in the controller itself. It works normally, but it's a pain in the ass the fact that I still need to write long $scopes because of the structure of the Google API. This is how I get the values in the controller:
app.controller('homeCt', ['$scope', 'Data', function ($scope, Data){
Data.news().success(function (data) {
$scope.totalNews = data.feed.entry.length;
});
}]);
Is there a way that I can set the factory service to pass me the data just using:
$scope.totalNews = Data.news()
Or at least removing the 'feed.entry'?
Data.news().success(function (data) {
$scope.totalNews = data.length;
});
Thank you very much!
example of service - resolve the success with the data you want
app.service('Data', ['$http', 'apiKeys', function($http, apiKeys){
var googleDocs = 'https://spreadsheets.google.com/feeds/list/';
this.news =function(){
return $http.get(googleDocs + apiKeys.googleDoc +'/1/public/values? alt=json', {cache: true})
.then(function(data){
return data.feed.entry.length;
});
}
}]);
the controller - since you already resolved the data in service hence..
app.controller('homeCt', ['$scope', 'Data', function ($scope, Data){
Data.news().then(function (data) {
$scope.totalNews = data;
});
}]);
working example
var app = angular.module('app', ['ionic'])
.service('Data', ['$http',
function($http) {
var googleDocs = 'https://spreadsheets.google.com/feeds/list/1aC1lUSxKatfxMKEy1erKDSAKgijSWOh77FDvKWhpwfg/1/public/values?alt=json';
this.news = function() {
return $http.get(googleDocs, {
cache: true
}).then(function(res) {
return res.data.feed.entry;
});
}
}
])
.controller('homeCt', ['$scope', 'Data',
function($scope, Data) {
Data.news().then(function(data) {
console.log(data);
})
}
]);
I'll give you a way of doing it, a way that I don't recommend at all (a service should not handle the scope), but for me it is the only way you have if you don't want to destroy the "async" of your ajax call :
app.factory('Data', ['$http', 'apiKeys', function($http, apiKeys){
var googleDocs = 'https://spreadsheets.google.com/feeds/list/';
return {
news:news,
updates: updates,
[...]
}
function news(scopeValue) {
$http.get(googleDocs + apiKeys.googleDoc +'/1/public/values?alt=json', {cache: true}).success(function(data){
scopeValue = data;
});
}]);
and then, call it that way in your controller :
Data.news($scope.totalNews);

BackboneJs fetch() Json to display on View

I am trying to use backbonejs to fetch() JSON data that sent from server to display it in a view. But it doesn't work.
Here is my backbonejs
$(function () {
var Service = Backbone.Model.extend({
url: "/api/album/1",
defaults: {
id: '1',
title: 'abc',
article: 'abc'
},
parse: function (response) {
return response.data;
}
});
// Create a collection of services
var ServiceList = Backbone.Collection.extend({
// Will hold objects of the Service model
url: "/api/album/1",
model: Service
});
var ServiceView = Backbone.View.extend({
tagName: 'li',
events: {
'click': 'toggleService'
},
initialize: function () {
this.listenTo(this.model, 'change', this.render);
},
render: function () {
this.$el.html('<input type="checkbox" value="1" name="' + this.model.get('title') + '" /> ' + this.model.get('title') + '<span>$' + this.model.get('artist') + '</span>');
this.$('input').prop('checked', this.model.get('checked'));
return this;
},
toggleService: function () {
this.model.toggle();
}
});
var App = Backbone.View.extend({
model: Service,
el: $('#main'),
initialize: function () {
this.model = new ServiceList();
this.model.fetch();
this.list = $('#services');
this.model.each(function (service) {
var view = new ServiceView({model: service});
this.list.append(view.render().el);
}, this);
},
render: function () {
return this;
}
});
new App();
});
Here is my JSON
{"data":{"id":"1","artist":"Gotye","title":"Making Mirrors"}}
Please ignore my bad naming convention in the backbonejs, i am trying to make it work
Try this
var App = Backbone.View.extend({
el: $('#main'),
initialize: function() {
var serviceList = new ServiceList(),
// if you don't have #services in html
//services = $(this.el).html('<div id="services"></div>'),
services = $(this.el).find('#services'),
serviceView;
serviceList.fetch({
success: function(collection) {
collection.each(function(model) {
serviceView = new ServiceView({
model: model
});
services.append(serviceView.render().el);
});
}
});
},
render: function() {
return this;
}
});
DEMO: http://jsbin.com/hiziqi/1/ in this demo I changed url to remote server

How to load more than one json file in angular

I am wondering how to load multiple .json files in to template.
In my example I have submissions from users and I do not want to store everything in one json file if possible.
How to grab some data from multiple json files?
here is my plunk example
I want to load users.json as well
var app = angular.module('myApp', []);
app.directive('contentItem', function ($compile,$parse) {
templates = {
image: 'image.html',
event: 'event.html',
article: 'article.html',
ad: 'ad.html',
discount: 'discount.html',
video: 'video.html'
}
var linker = function(scope, element, attrs) {
scope.setUrl = function(){
return templates[scope.content.content_type];
}
}
return {
restrict: "E",
replace: true,
link: linker,
scope: {
content: '='
},
templateUrl: 'main.html'
};
});
function ContentCtrl($scope, $http) {
"use strict";
$scope.url = 'content.json';
$scope.content = [];
$scope.fetchContent = function() {
$http.get($scope.url).then(function(result){
$scope.content = result.data;
});
}
$scope.fetchContent();
}
Help appreciated
You can request for JSON either from the controller like:
app.controller('myController', function($scope, $http){
$scope.users = [];
$scope.getUsers = function() {
$http({method: 'JSONP', url: "users.json?query=?callback=JSON_CALLBACK&query="+ $scope.searchString}).
success(function(data, status) {
$scope.users = data;
}).
error(function(data, status) {
console.log(data || "Request failed");
});
};
and the other approach (better one) would be to make use of angular factory to fetch the JSON file.
myApp.factory('getUsersFactory',['$http',function($http){
return {
getUsers: function(callback){
$http({method: 'JSONP', url: "users.json?query=?callback=JSON_CALLBACK&query="+ $scope.searchString}).success(callback);
}
}
}]);
where now you can include this factory as a dependency and get the user data and assign that in the callback function.

How to render jsonp fetched in BackboneJS?

I'm new in BackboneJS, and I can't render information from JSONP. If I put the data into a data.json and I fetch it, the count appears in the console, but when I use JSONP never re-render.
I don't know if is some kind of delay for obtain the data, but the event of "change" and "reset" are not being trigged by the collection to re-render the view.
The code I have is the next:
// Collection
define([
'underscore',
'backbone',
'models/EstablecimientoModel'],function(_, Backbone, EstablecimientoModel){
var EstablecimientoCollection = Backbone.Collection.extend({
model: EstablecimientoModel,
initialize: function(models, options) {
console.log("Establecimiento initialize");
},
url: function() {
return '../js/establecimientos.json';
//return 'http://localhost:3000/establecimiento';
},
parse: function(data) {
console.log("End of loading data " + JSON.stringify(data) + " datos");
return data;
},
});
return EstablecimientoCollection;
});
// Router
define([
'jquery',
'underscore',
'backbone',
'views/establecimiento/EstablecimientoView',
'jqm'
], function($, _, Backbone,EstablecimientoView) {
'use strict';
var Router = Backbone.Router.extend({
//definition of routes
routes: {
'nearMe' : 'nearMe',
},
nearMe: function(actions) {
var estaColl = new EstablecimientoCollection();
var establecimientoView = new EstablecimientoView({ collection: estaColl });
//estaColl.fetch();
//establecimientoView.render();
this.changePage(establecimientoView);
},
init: true,
changePage: function(view) {
//add the attribute data-role="page" for each view's div
$(view.el).attr('data-role','page');
view.render();
// append to the DOM
$('body').append($(view.el));
var transition = $.mobile.defaultPageTransition;
if(this.firstPage) {
transition = 'none';
this.firstPage = false;
}
// Remove page from DOM when it’s being replaced
$('div[data-role="page"]').on('pagehide', function (event, ui) {
$(this).remove();
});
$.mobile.changePage($(view.el), { transition: transition, changeHash: false });
} // end of changePage()
});
return Router;
});
// View
define([
'jquery',
'underscore',
'backbone',
'collections/EstablecimientoCollection',
'text!templates/establecimiento/establecimientoTemplate.html'
],function($, _, Backbone, EstablecimientoCollection, establecimientoTemplate) {
var EstablecimientoView = Backbone.View.extend({
initialize: function() {
var self = this;
_.bindAll(this,"render");
this.collection.on("change",self.render);
this.collection.fetch({ dataType: 'jsonp', success: function(){ self.render() }});
}, //end of initialize()
template: _.template(establecimientoTemplate),
render: function(eventName) {
console.log("render");
console.log(this.collection.length);
return this;
}, //end of render()
});
return EstablecimientoView;
});
When you fetch your data, make sure you're setting the dataType for your fetch call. Fetch is wrapping a jQuery/Zepto ajax call, so you'll need to set the same parameters you would with those.
this.collection.fetch({
reset: true,
dataType: 'jsonp',
success: function () {
// do stuff
}
});
Also, I'd have your view listen for the events published by the collection rather than calling the view's render directly from the fetch's success callback.

Backbonejs add to collection only if fetch data different

I am writing a small app that calls a json request that has data about a track that is playing for a music player. Every 2-3 minutes that track on the json request changes. I am trying to get backbone to only fire and add another model to my collection if the previous entry called is different. Here is my code so far, however it keeps rendering the same data
// Model: Track
//
//
window.Track = Backbone.Model.extend({});
// Collection: Tracks
//
//
window.Tracks = Backbone.Collection.extend({
model: Track,
url: "api/nowplaying/1.json",
parse: function (response) {
return response.response.body;
}
});
// View: MetaDataView
//
//
window.MetaDataView = Backbone.View.extend({
template: "#metadata-template",
tagName: 'li',
className: 'metadata',
initialize: function() {
_.bindAll(this, 'render');
this.model.bind('change', this.render);
this.initializeTemplate();
},
initializeTemplate: function() {
this.template = _.template($(this.template).html());
},
render: function() {
$(this.el).html(this.template(this.model.toJSON()));
return this;
}
});
// View: MetaDataLibraryView
//
//
window.MetaDataLibraryView = Backbone.View.extend({
tagName: 'section',
className: 'metadata-library',
initialize: function() {
_.bindAll(this, 'render', 'startup', 'renderNew');
this.template = _.template($('#metadata-library-template').html());
//this.collection.bind('reset', this.render);
this.collection.on('add', this.renderNew, this);
this.startup();
},
startup: function() {
var e = this;
window.setInterval(function () {
console.log('fetching');
e.collection.fetch({update: true, remove:false, add: true});
}, 2000);
},
renderNew: function(newModel) {
var collection = this.collection;
$metadata = this.$(".metadata-library");
var view = new MetaDataView({ model: newModel, collection: collection });
$metadata.append(view.render().el);
return this;
},
render: function() {
var $metadata,
collection = this.collection;
$(this.el).html(this.template({}));
$metadata = this.$(".metadata-library");
this.collection.each(function(schedule) {
var view = new MetaDataView({ model: schedule,
collection: collection });
$metadata.append(view.render().el);
});
return this;
}
});
I have found posts on stackoverflow talking about the possibility of using collection fetch options like {update: true, remove:false, add: true}. How would I get the data to be rendered only if the model changes that's being fetch?
Something like this should work
startup: function() {
window.setInterval(function () {
console.log('fetching');
var track = new Track();
track.fetch()
.done(function() {
if(!this.isSamePrevTrack(track)) {
e.collection.add(track);
}
}.bind(this));
}.bind(this), 2000);
},
isSamePrevTrack: function(track) {
if(!this.prevTrack) {
this.prevTrack = track;
return false;
}
// Do some test to see if the track is the same
// ie. return this.prevTrack.get('id') === track.get('id');
});