Knockout model breaking on array length in computed observable - arrays

Slowly extending my nested form at http://jsfiddle.net/gZC5k/1004/ I'm running into a difficulty getting to work ko.computed that I want to use to compute the number of children in the nested JSON array. The code that breaks is at // this breaks
self.contacts = ko.observableArray(ko.utils.arrayMap(contacts, function (contact) {
return {
firstName: ko.observable(contact.firstName),
lastName: ko.observable(contact.lastName),
isKey: ko.observable(contact.isKey),
gender: ko.observable(contact.gender),
phones: ko.observableArray(ko.utils.arrayMap(contact.phones, function (phone) {
return {
type: ko.observable(phone.type),
number: ko.observable(phone.number),
calls: ko.observableArray(phone.calls),
callsVisible: ko.observable(false)
};
})),
addresses: ko.observableArray(contact.addresses),
optionGender: optionGender,
phonesVisible: ko.observable(false),
addressesVisible: ko.observable(false),
// this breaks
// numberOfPhones: ko.computed(function (contact) {
// return contact.phones.length;
// });
};
}));
Where is the error?

I think that you're going to need to create each contact as a function:
var ContactModel = function(contact)
{
var self = this;
self.firstName = ko.observable(contact.firstName);
self.lastName = ko.observable(contact.lastName);
self.isKey = ko.observable(contact.isKey);
self.gender = ko.observable(contact.gender);
self. phones = ko.observableArray(ko.utils.arrayMap(contact.phones, function (phone) {
return {
type: ko.observable(phone.type),
number: ko.observable(phone.number),
calls: ko.observableArray(phone.calls),
callsVisible: ko.observable(false)
};
}));
self.addresses = ko.observableArray(contact.addresses);
self.optionGender = optionGender;
self.phonesVisible = ko.observable(false);
self.addressesVisible = ko.observable(false);
self.numberOfPhones = ko.computed(function () {
return self.phones().length;
});
return self;
};
And create it like this:
self.contacts = ko.observableArray(ko.utils.arrayMap(contacts, function (contact) {
return new ContactModel(contact);
}));

You can try this:
numberOfPhones: ko.computed(function () {
return contact.phones.length;
})

Related

How can I link data coming from an API to a column in a data table in Angularjs

There is a data table which is getting data from an API.
This API is responsible for populating every column on the data table. I added a new column named "Project Involved" which should get filled by the data "ProjectNames" coming from API.
The problem that am facing is- I am not able to link this data to the column on data table.
There are other columns that are getting populated.
This is the column name:
{
data: 'ProjectsInvolved',
title: $translate.instant('Projects involved'),
width: 80
}
This is where we link the API to the data table:
"use strict";
angular
.module('project')
.controller(
'ProjectPermissionsGridController',
function (
$scope,
roleConstants,
$timeout,
FormHelperService,
$translate,
$mdDialog,
logger,
projectConstants,
DateHelperService,
ResourceService,
ProjectService,
$stateParams,
$filter
) {
var pm = this;
pm.resources = [];
pm.copyOfAllResources = [];
pm.pmFormBtn = $translate.instant('btn.save');
pm.projectMemberList = [];
pm.IsProjectManager = false;
pm.maxAllowedHoursLimit = projectConstants.PROJECT_COST_PER_HOUR;
pm.projectMembersData = {
EmpID: '',
Read: roleConstants.NONE,
Write: roleConstants.NONE,
IsProjectManager: false,
// ProjectNames: pm.projectMemberList.ProjectNames
ProjectNames: ''
};
pm.showNoErrorsPerm = true;
pm.maxDate = DateHelperService.setTimeFormattedObject(new Date());
var currentIndex = '';
pm.isProjectMemberEdit = false;
var oldProjectMemberData = {};
pm.udpateResourcePersmissions = function () {
if (pm.projectMembersData.IsProjectManager) {
pm.projectMembersData.Read = roleConstants.ALL;
pm.projectMembersData.Write = roleConstants.ALL;
}
};
pm.initDataTableConfig = function (column, config, api) {
$scope.dtColumns = column;
$scope.dtConfig = config;
$scope.dtApiProjectMembers = api;
};
// Catching the event and binding the data
$scope.$on('evt.project-member-details', function (e, projectMembers) {
pm.projectMemberList = projectMembers;
pm.bindDataToGrid(false, projectMembers);
});
$scope.$on('evt.resources-list', function (e, resources) {
pm.resources = resources;
pm.copyOfAllResources = resources;
});
// On change to remove the cost per hour required validation.
pm.removeCostperHourValidation = function () {
if (!pm.projectMembersData.CostPerHour) {
pm.projectMembersData.CostPerHour = null;
}
if (
parseFloat(pm.projectMembersData.CostPerHour) >
pm.maxAllowedHoursLimit
) {
pm.projectMembersData.CostPerHour = pm.maxAllowedHoursLimit;
}
};
/**
* Add / update new data to project members grid.
*/
pm.addNewProjectMember = function (valid, $event) {
if (!valid) {
$scope.showNoErrorsPerm = false;
return false;
}
pm.projectMembersData.ProjectMember =
FormHelperService.getSelectedObject(
pm.resources,
'EmpID',
pm.projectMembersData.EmpID,
false
).EmpFirstName +
' ' +
FormHelperService.getSelectedObject(
pm.resources,
'EmpID',
pm.projectMembersData.EmpID,
false
).EmpLastName;
pm.projectMembersData.ReadText = projectConstants.PERMISSION_TYPE_OBJ[
pm.projectMembersData.Read
]
? projectConstants.PERMISSION_TYPE_OBJ[pm.projectMembersData.Read]
: '--';
pm.projectMembersData.WriteText = projectConstants.PERMISSION_TYPE_OBJ[
pm.projectMembersData.Write
]
? projectConstants.PERMISSION_TYPE_OBJ[pm.projectMembersData.Write]
: '--';
// pm.projectMembersData.ProjectsInvolved = 'OSMOSYS';
if ($scope.isProjectEdit) {
membersEditProjectForm();
} else {
memberNewProjectForm($event);
}
};
/**
* Function to be executed in the new project page.
* #param {*} event
*/
function memberNewProjectForm($event) {
// Setting this value at the time of clicking on edit button.
if (pm.isProjectMemberEdit) {
oldProjectMemberData = {};
angular.extend(
pm.projectMemberList[currentIndex],
pm.projectMembersData
);
pm.pmFormBtn = $translate.instant('btn.add');
} else {
pm.projectMembersData.CreatedOn =
DateHelperService.setTimeFormatString(new Date());
pm.projectMemberList.splice(0, 0, pm.projectMembersData);
// remove that element from employees dropdown to not to select it again
enableOrDisableEmployee(pm.projectMembersData.EmpID, true);
}
angular.element($event.target).data('isInvalid', true);
$scope.showNoErrorsPerm = true;
pm.projectMembersData = {
EmpID: '',
Read: roleConstants.NONE,
Write: roleConstants.NONE,
IsProjectManager: false,
ProjectNames: ''
};
pm.bindDataToGrid(!pm.isProjectMemberEdit, pm.projectMemberList);
$scope.updateProjectMembers({ projectMembers: pm.projectMemberList });
pm.isProjectMemberEdit = false;
}
/**
* Function to add a new project member
* #param {*} data
* #param {*} projectMemberDetails
*/
function addProjectMember(data, projectMemberDetails) {
ProjectService.addProjectMember(data).then(function (response) {
if (response.isValid()) {
pm.projectMemberList.splice(0, 0, pm.projectMembersData);
pm.bindDataToGrid(false, pm.projectMemberList);
enableOrDisableEmployee(pm.projectMembersData.EmpID, true);
resetPMForm();
$scope.$emit('evt.update-project-managers', projectMemberDetails);
logger.success('Resource has been added to the project');
} else {
var errorMsg = response.getMessage(
$translate.instant('prj.resource'),
$translate.instant('event.adding')
);
logger.error(errorMsg);
}
});
}
/**
* Function to update a project member's details
* #param {*} data
* #param {*} projectMemberDetails
*/
function updateProjectMember(data, projectMemberDetails) {
ProjectService.updateProjectMember(data).then(function (response) {
if (response.isValid()) {
angular.extend(
pm.projectMemberList[currentIndex],
pm.projectMembersData
);
pm.pmFormBtn = $translate.instant('btn.add');
pm.bindDataToGrid(pm.isProjectMemberEdit, pm.projectMemberList);
enableOrDisableEmployee(pm.projectMembersData.EmpID, true);
$scope.$emit('evt.update-project-managers', projectMemberDetails);
resetPMForm();
pm.isProjectMemberEdit = false;
logger.success("Project member's details have been updated.");
} else {
var errorMsg = response.getMessage(
$translate.instant('prj.project_members_details'),
$translate.instant('event.updating')
);
logger.error(errorMsg);
}
});
}
/**
* Function to be executed in the project details form
*/
function membersEditProjectForm() {
var projectMemberDetails = {
empID: pm.projectMembersData.EmpID,
name: pm.projectMembersData.ProjectMember,
isProjectManager: pm.projectMembersData.IsProjectManager,
};
var members = [];
// Adding the projectCode to project member's data
pm.projectMembersData.ProjectCode = $stateParams.projectID;
// Creating the UserID property as the add and update project members API methods expects the UserID and not
// the EmpID
pm.projectMembersData.UserID = pm.projectMembersData.EmpID;
// Adding the current project memeber to the members array as the API methods for the
// add and update project member expects an array
members.push(pm.projectMembersData);
if (pm.isProjectMemberEdit) {
updateProjectMember(members, projectMemberDetails);
} else {
addProjectMember(members, projectMemberDetails);
}
}
pm.eleFocus = function () {
FormHelperService.searchElementFocus();
};
// Clearing the searched item when closing the dropdown
pm.clearSearchTerm = function () {
pm.projectMemberSearchText = '';
};
/**
* return the search results for auto complete controls.
*/
pm.querySearch = function (
query,
list,
listObjProp,
listObjPropName,
splitObjProp
) {
if (!list || list === '') {
list = [];
}
if (listObjPropName) {
var queryObj = {};
queryObj[listObjPropName] = query;
if (splitObjProp) {
var listOjProp = listObjProp.split('.');
pm[listOjProp[0]][listOjProp[1]] = $filter('filter')(
list,
queryObj
);
} else {
pm[listObjProp] = $filter('filter')(list, queryObj);
}
} else {
pm[listObjProp] = $filter('filter')(list, query);
}
};
// Fetching the row and row index when clicking on edit button and showing the details in form
angular.element('table').on('click', '.edit-project-member', function () {
pm.projectMembersData = $scope.dtApiProjectMembers.getRowData(
this.parentElement
);
pm.IsProjectManager = pm.projectMembersData.IsProjectManager;
if (pm.projectMembersData.EmpCostPerHour) {
pm.projectMembersData.EmpCostPerHour =
typeof pm.projectMembersData.EmpCostPerHour === 'string'
? pm.projectMembersData.EmpCostPerHour
: pm.projectMembersData.EmpCostPerHour.toFixed(2);
}
if (pm.projectMembersData.CostPerHour) {
pm.projectMembersData.CostPerHour =
typeof pm.projectMembersData.CostPerHour === 'string'
? pm.projectMembersData.CostPerHour
: pm.projectMembersData.CostPerHour.toFixed(2);
}
// Adding the code as IsProjectManager property is mandatory and sometimes may not be defined
if (!pm.projectMembersData.IsProjectManager) {
pm.projectMembersData.IsProjectManager = false;
}
angular.copy(pm.projectMembersData, oldProjectMemberData);
pm.isProjectMemberEdit = true;
pm.pmFormBtn = $translate.instant('btn.update');
currentIndex = $scope.dtApiProjectMembers.getRowIndex(
this.parentElement
);
});
// Showing an alert and Deleting the row data
angular
.element('table')
.on('click', '.delete-project-member', function () {
var deleteRowIndex = $scope.dtApiProjectMembers.getRowIndex(
this.parentElement
);
var deleteRowData = $scope.dtApiProjectMembers.getRowData(
this.parentElement
);
showConfirmDialog(deleteRowIndex, deleteRowData);
});
function showConfirmDialog(deleteRowIndex, deleteRowData) {
var confirm = $mdDialog
.confirm({
onComplete: function afterShowAnimation() {
var $dialog = angular.element(
document.querySelector('md-dialog')
);
var $dialogContent = $dialog.find('md-dialog-content');
var $actionsSection = $dialog.find('md-dialog-actions');
var $cancelButton = $actionsSection.children()[0];
var $confirmButton = $actionsSection.children()[1];
angular.element($dialogContent).addClass('custom-confirm-class');
angular.element($confirmButton).addClass('md-raised md-warn');
angular.element($cancelButton).addClass('md-raised');
},
})
.title($translate.instant('prj.confirm_pm_delete'))
.textContent(
'Are you sure you want to delete the selected project member?' +
deleteRowData.ProjectMember
)
.ariaLabel($translate.instant('prj.confirm_pm_delete'))
.ok($translate.instant('bar.delete'))
.cancel($translate.instant('bar.cancel'));
$mdDialog.show(confirm).then(function () {
pm.isProjectMemberEdit = false;
if ($scope.isProjectEdit) {
var projectMemberData = [
{
ProjectCode: $stateParams.projectID,
UserID: deleteRowData.EmpID,
},
];
ProjectService.deleteProjectMember(projectMemberData).then(
function (response) {
if (response.isValid()) {
logger.success(
$translate.instant('prj.project_member_removed_success_msg')
);
deleteProjectMember(deleteRowIndex, deleteRowData);
if (deleteRowData.IsProjectManager) {
$scope.$emit(
'evt.project-manager-removed',
deleteRowData.EmpID.toString()
);
}
} else {
var errorMsg = response.getMessage(
$translate.instant('prj.project_member'),
$translate.instant('event.deleting')
);
logger.error(errorMsg);
}
}
);
} else {
deleteProjectMember(deleteRowIndex, deleteRowData);
$scope.updateProjectMembers({
projectMembers: pm.projectMemberList,
});
}
pm.pmFormBtn = $translate.instant('btn.save');
pm.projectMembersData = {
EmpID: '',
Read: roleConstants.NONE,
Write: roleConstants.NONE,
IsProjectManager: false,
};
});
}
function deleteProjectMember(deleteRowIndex, deleteRowData) {
pm.projectMemberList.splice(deleteRowIndex, 1);
pm.bindDataToGrid(false, pm.projectMemberList);
var oldEmpId = deleteRowData.EmpID;
// Add that element to employees dropdown to be able to select it again
enableOrDisableEmployee(oldEmpId, false);
}
function enableOrDisableEmployee(empId, isEnable) {
for (var j = 0; j < pm.resources.length; j++) {
if (pm.resources[j].EmpID === empId) {
pm.resources[j].isDisabled = isEnable;
return;
}
}
}
pm.isReadPermissionLevelLess = function (level) {
return pm.projectMembersData.Read < level ? true : false;
};
/**
* To change the write permission default value based on the read permission
* Ex : If read - own, then write should not be all
*/
pm.changeWriteDefaultValue = function () {
if (pm.projectMembersData.Read < pm.projectMembersData.Write) {
pm.projectMembersData.Write = pm.projectMembersData.Read;
}
};
/**
* Get the cost per hour of an employee when the employee value is changed
*/
pm.getCostPerHour = function () {
ResourceService.getEmployeeCostPerHour(
pm.projectMembersData.EmpID
).then(
function (response) {
if (response.isValid()) {
var costPerHour = response.getData();
if (costPerHour && costPerHour[0]) {
pm.projectMembersData.EmpCostPerHour =
costPerHour[0].CostPerHour.toFixed(2);
pm.projectMembersData.CostPerHour =
pm.projectMembersData.EmpCostPerHour;
}
}
},
function (error) {
logger.error(error);
}
);
};
$scope.$on("evt.clear-pm-members-grids-data", function () {
pm.projectMemberList = [];
pm.bindDataToGrid(false, pm.projectMemberList);
});
// Binding the data to grid with updated data.
pm.bindDataToGrid = function (reOrder, projectMembers) {
pm.projectMemberList = projectMembers;
if (pm.projectMemberList && pm.projectMemberList.length) {
var currPage = $scope.dtApiProjectMembers.getPageInfo()['page'];
$scope.dtApiProjectMembers.bindData(pm.projectMemberList);
currPage = currPage >= 0 ? currPage : 0;
if (reOrder) {
$scope.dtApiProjectMembers.orderByColumn([[1, 'desc']]);
} else {
$scope.dtApiProjectMembers.setPage(currPage);
}
} else {
$scope.dtApiProjectMembers.bindData([]);
}
};
function resetPMForm() {
$scope.showNoErrorsPerm = true;
$scope.vm.pmData.$setPristine();
$scope.vm.pmData.$setUntouched(true);
pm.projectMembersData = {
EmpID: '',
Read: roleConstants.NONE,
Write: roleConstants.NONE,
IsProjectManager: false,
};
}
$scope.$on('evt.reset-project-members-form', function () {
resetPMForm();
});
}
);
I tried linking data when adding new resource- I can see project getting linked. I hard coded this to see if I was working on the right container.

Angularsjs cannot find service function

My filterProducts function makes a call to findIntersection which is present but I get an error findIntersection is undefined.
angular.module('BrandService', [])
.service('BrandService', function ($filter, DataService) {
var productDb;
var products;
return {
filterProducts(brands, priceRange) {
var filteredProducts = [];
var brandProducts = [];
var priceProducts = [];
var productsArray = [];
var brandChecked = false;
var priceChecked = false;
angular.forEach(brands, function (brand) {
if (brand.checked) {
brandChecked = true;
angular.extend(brandProducts,
$filter('filter')(productDb, { 'brand': brand.name }));
}
if (brandChecked) {
productsArray.push(brandProducts);
console.log('brandProducts = ', brandProducts)
}
});
angular.forEach(priceRange, function (price) {
if (price.checked) {
priceChecked = true;
let filteredProductDb = productDb.filter((prod) => {
return (prod.price >= price.low && prod.price <= price.high);
});
angular.extend(priceProducts, filteredProductDb);
}
});
if (priceChecked) {
productsArray.push(priceProducts);
// console.log('priceProducts = ', priceProducts)
}
if (!brandChecked && !priceChecked) {
filteredProducts = products;
} else {
if (productsArray.length > 1) {
filteredProducts = findIntersection(productsArray);
} else {
filteredProducts = productsArray[0];
}
}
return filteredProducts;
},
findIntersection(productsArray) {
console.log('findIntersection called')
var filteredProducts = [];
var filteredSet = new Set();
for(var i=0; i < productsArray.length - 1; i++) {
var products1 = productsArray[i];
var products2 = productsArray[i+1];
angular.forEach(products1, function(product1) {
angular.forEach(products2, function(product2) {
if(product1._id == product2._id) {
filteredSet.add(product1);
}
});
});
}
filteredProducts = Array.from(filteredSet);
return filteredProducts;
}
}
})
My filterProducts function makes a call to findIntersection which is present but I get an error findIntersection is undefined.
My filterProducts function makes a call to findIntersection which is present but I get an error findIntersection is undefined.
You are returning a javascript object with properties. You are not defining global functions.
You need to store the service returned before :
var service = { findProducts: ... , findIntersection: ... };
return service;
And instead of calling findIntersection, call service.findIntersection.
You have to make a reference to local object.
Simply change this: filteredProducts = findIntersection(productsArray);
to this: filteredProducts = this.findIntersection(productsArray);

My service is returning the function's text and not an object

I have a service to share an object in my app... I want to post that object to the mongo db but when I call the function that should return the object it gives me the function's text.
The service is here:
angular.module('comhubApp')
.service('markerService', function () {
this.markers = [];
this.newMarker = { title: '',
description: '',
lat: '',
lon: '',
user: '',
created_at: '' };
// This is supposed to return the marker object
this.newMarker = function () {
return this.newMarker;
};
this.setTitle = function (title) {
this.newMarker.title = title;
console.log('title service set: ' + title);
};
this.setDescription = function (description) {
this.newMarker.description = description;
console.log('Description service set: ' + description);
};
this.setLat = function (lat) {
this.newMarker.lat = lat;
console.log('lat service set: ' + lat);
};
this.setLon = function (lon) {
this.newMarker.lon = lon;
console.log('lon service set: ' + lon);
};
this.reset = function () {
this.newMarker = { title: '',
description: '',
lat: '',
lon: '',
user: '',
created_at: ''};
}
this.setMarkers = function (markers) {
this.markers = markers;
}
this.markers = function () {
return this.markers;
}
this.addMarker = function (marker) {
//todo append marker
}
});
newMarker returns:
this.newMarker = function () {
return this.newMarker;
};
The Controller using the service is here
$scope.addMarker = function() {
if($scope.newMarker.title === '') {
console.log('newMarker title is empty');
return;
}
markerService.setTitle($scope.newMarker.title);
markerService.setDescription($scope.newMarker.description);
console.log(markerService.newMarker());
// $http.post('/api/markers', { name: $scope.newMarker });
// $scope.newMarker = '';
};
$scope new marker is form data.. i tried to put that right into my service with no success. Instead I out the form data into the controller then push it to the service. If there is a better way to do that please let me know.
If this service is bad in any other way let me know I am new to all this and so I followed another answer I saw on here.
You are overriding your object with function. Just give them different names and it should work just fine.
this.newMarker = { ... };
this.getNewMarker = function () { return this.newMarker };
EDIT:
You should also always create new instance from marker. Otherwise you just edit the same object all the time. Here is example I made. Its not best practice but hope you get the point.
angular.module('serviceApp', [])
.factory('Marker', function () {
function Marker() {
this.title = '';
this.descrpition = '';
}
// use setters and getters if you want to make your variable private
// in this example we are not using these functions
Marker.prototype.setTitle = function (title) {
this.title = title;
};
Marker.prototype.setDescription = function (description) {
this.description = description;
};
return Marker;
})
.service('markerService', function (Marker) {
this.markers = [];
this.getNewMarker = function () {
return new Marker();
}
this.addMarker = function (marker) {
this.markers.push(marker);
}
})
.controller('ServiceCtrl', function ($scope, markerService) {
$scope.marker = markerService.getNewMarker();
$scope.addMarker = function () {
markerService.addMarker($scope.marker);
$scope.marker = markerService.getNewMarker();
}
$scope.markers = markerService.markers;
});
You could also create Marker in controller and use markerService just to store your object.
And working demo:
http://jsfiddle.net/3cvc9rrs/
So, that function is the problem. I was blindly following another example and it was wrong in my case. The solution is to remove that function and access markerService.newMarker directly.
I am still a big enough noob that I am not sure why the call was returning the function as a string. It seems to have something to do with how it is named but it is just a guess.

Unable to get my data from $firebaseObject using AngularFire in a controller. View/ng-repeat works fine

I have different sections in Firebase with normalized data, and I have routines to get the information, but I cannot loop through the returned records to get data. I want to use the keys in the $firebaseArray() to get data from other $firebaseObject().
GetOneTeam() .... {
var DataRef = GetFireBaseObject.DataURL(Node + '/'); // xxx.firebaseio.com/Schedules/
var OneRecordRef = DataRef.child(Key); // Schedule Key - 1
return $firebaseObject(OneRecordRef);
}
...
var Sched = GetOneSchedule('Schedules', 1);
... // For Loop getting data - Put in HomeId
var TeamRec = GetOneTeam('Teams', HomeId);
var Name = TeamRec.TeamName; // Does not TeamName value from Schedule/1
The following is more of the actual code in case the snippet above is not clear enough. Sample common routine for getting data:
angular.module('MyApp')
.constant('FIREBASE_URL', 'https://xxxxxxxx.firebaseio.com/');
angular.module('MyApp')
.factory('GetFireBaseObject', function(FIREBASE_URL) {
return {
BaseURL: function() {
return new Firebase(FIREBASE_URL);
},
DataURL: function(Node) {
return new Firebase(FIREBASE_URL + Node);
}
};
}
);
// Common code for getting Array/Object from Firebase.
angular.module('MyApp')
.factory("FireBaseData", ["$firebaseArray", "$firebaseObject", "GetFireBaseObject",
function($firebaseArray, $firebaseObject, GetFireBaseObject) {
return {
AllRecords: function(Node) {
var DataRef = GetFireBaseObject.DataURL(Node + '/');
return $firebaseArray(DataRef);
},
OneRecordAllChildren: function(Node, Key) {
var DataRef = GetFireBaseObject.DataURL(Node + '/');
var ParentRecordRef = DataRef.child(Key);
return $firebaseArray(ParentRecordRef);
},
OneRecord: function(Node, Key) {
var DataRef = GetFireBaseObject.DataURL(Node + '/');
var OneRecordRef = DataRef.child(Key);
return $firebaseObject(OneRecordRef);
},
AddRecord: function(Node, Record) {
var DataRef = GetFireBaseObject.DataURL(Node + '/');
var AddRecordRef = DataRef.child(Record.Key);
AddRecordRef.update(Record);
return $firebaseObject(AddRecordRef); // Return Reference to added Record
},
DeleteRecord: function(Node, Key) {
var DataRef = GetFireBaseObject.DataURL(Node + '/');
var DeleteRecordRef = DataRef.child(Key);
DeleteRecordRef.remove();
}
};
}
]);
Individual Controller's retrieval of records from firebase.io:
angular.module('MyApp').service("ScheduleData", ["FireBaseData",
function(FireBaseData) {
var DataPath = 'Schedules';
this.AllSchedules = function() {
return FireBaseData.AllRecords(DataPath);
};
this.AddSchedule = function(GameInfo) {
return FireBaseData.AddRecord(DataPath, GameInfo);
};
this.DeleteSchedule = function(GameKey) {
FireBaseData.DeleteRecord(DataPath, GameKey);
};
this.GetOneSchedule = function(GameKey) {
return FireBaseData.OneRecord(DataPath, GameKey);
};
}
]);
// Structure of a record, including named fields to come from another object (Team/Venue using the OneRecord FireBaseData call to get a $firebaseObject
angular.module('MyApp').factory("ScheduleRecord", function() {
return {
Clear: function(GameInfo) {
GameInfo.Key = "";
GameInfo.HomeTeamId = "";
GameInfo.HomeTeamName = "";
GameInfo.AwayTeamId = "";
GameInfo.AwayTeamName = "";
GameInfo.VenueId = "";
GameInfo.VenueName = "";
GameInfo.GameDate = "";
GameInfo.GameTime = "";
}
};
}
);
Controller module start:
angular.module('MyApp').controller('ScheduleCtrl', ["$scope", "ScheduleData", "ScheduleRecord", "TeamData", "VenueData",
function ($scope, ScheduleData, ScheduleRecord, TeamData, VenueData) {
var ClearEditData = function() {
$scope.ScheduleEditMode = false;
ScheduleRecord.Clear($scope.schedule);
};
var GameSchedules = ScheduleData.AllSchedules();
This next piece is where my question lies. Once the promise returns the static schedule list, I want to loop through each record and translate the Team Id (Home/Away) and Venue Id to the names.
GameSchedules.$loaded().then(function() {
angular.forEach(GameSchedules, function(GameInfo) {
var HomeTeam = TeamData.GetOneTeam(GameInfo.HomeTeamId);
GameInfo.HomeTeamName = HomeTeam.Name;
The GetOneTeam returns a $firebaseObject, based on the HomeTeamId child record. This returns null all the time.
This is the TeamData.GetOneTeam return using the FireBaseData as well.
angular.module('MyApp').service("TeamData", ["FireBaseData",
function(FireBaseData) {
var DataPath = 'Teams';
this.AllTeams = function() {
return FireBaseData.AllRecords(DataPath);
};
this.AddTeam = function(TeamInfo) {
return FireBaseData.AddRecord(DataPath, TeamInfo);
};
this.DeleteTeam = function(TeamKey) {
FireBaseData.DeleteRecord(DataPath, TeamKey);
};
this.GetOneTeam = function(TeamKey) {
return FireBaseData.OneRecord(DataPath, TeamKey);
};
}
]);
As I have a Firebase Object, how can I get my named data objects from the $firebaseObject?
This is a mess. Use $firebaseArray for collections, not $firebaseObject. Most of these strange wrapper factories are unnecessary. AngularFire services already have methods for add, remove, and so on, and all these factories attempt to make AngularFire into a CRUD model and don't actually provide any additional functionality or enhancements.
app.factory('Ref', function(FIREBASE_URL) {
return new Firebase(FIREBASE_URL);
});
app.factory('Schedules', function($firebaseArray, Ref) {
return $firebaseArray(Ref.child('Schedules'));
});
// or if you want to pass in the path to the data...
//app.factory('Schedules', function($firebaseArray, Ref) {
// return function(pathToData) {
// return $firebaseArray(Ref.child(pathToData));
// };
//});
app.factory('Schedule', function($firebaseObject, Ref) {
return function(scheduleId) {
return $firebaseObject(Ref.child('Schedules').child(scheduleId));
}
});
app.controller('...', function(Schedules, Schedule, Ref) {
$scope.newSchedule(data) {
Schedules.$add(data);
};
$scope.removeSchedule(key) {
Schedules.$remove(key);
};
$scope.updateSchedule(key, newWidgetValue) {
var rec = Schedules.$getRecord(key);
rec.widgetValue = newWidgetValue;
Schedules.$save(rec);
};
// get one schedule
var sched = Schedule(key);
sched.$loaded(function() {
sched.widgetValue = 123;
sched.$save();
});
});

accessing items in firebase

I'm trying to learn firebase/angularjs by extending an app to use firebase as the backend.
My forge looks like this
.
In my program I have binded firebaseio.com/projects to $scope.projects.
How do I access the children?
Why doesn't $scope.projects.getIndex() return the keys to the children?
I know the items are in $scope.projects because I can see them if I do console.log($scope.projects)
app.js
angular.module('todo', ['ionic', 'firebase'])
/**
* The Projects factory handles saving and loading projects
* from localStorage, and also lets us save and load the
* last active project index.
*/
.factory('Projects', function() {
return {
all: function () {
var projectString = window.localStorage['projects'];
if(projectString) {
return angular.fromJson(projectString);
}
return [];
},
// just saves all the projects everytime
save: function(projects) {
window.localStorage['projects'] = angular.toJson(projects);
},
newProject: function(projectTitle) {
// Add a new project
return {
title: projectTitle,
tasks: []
};
},
getLastActiveIndex: function () {
return parseInt(window.localStorage['lastActiveProject']) || 0;
},
setLastActiveIndex: function (index) {
window.localStorage['lastActiveProject'] = index;
}
}
})
.controller('TodoCtrl', function($scope, $timeout, $ionicModal, Projects, $firebase) {
// Load or initialize projects
//$scope.projects = Projects.all();
var projectsUrl = "https://ionic-guide-harry.firebaseio.com/projects";
var projectRef = new Firebase(projectsUrl);
$scope.projects = $firebase(projectRef);
$scope.projects.$on("loaded", function() {
var keys = $scope.projects.$getIndex();
console.log($scope.projects.$child('-JGTmBu4aeToOSGmgCo1'));
// Grab the last active, or the first project
$scope.activeProject = $scope.projects.$child("" + keys[0]);
});
// A utility function for creating a new project
// with the given projectTitle
var createProject = function(projectTitle) {
var newProject = Projects.newProject(projectTitle);
$scope.projects.$add(newProject);
Projects.save($scope.projects);
$scope.selectProject(newProject, $scope.projects.length-1);
};
// Called to create a new project
$scope.newProject = function() {
var projectTitle = prompt('Project name');
if(projectTitle) {
createProject(projectTitle);
}
};
// Called to select the given project
$scope.selectProject = function(project, index) {
$scope.activeProject = project;
Projects.setLastActiveIndex(index);
$scope.sideMenuController.close();
};
// Create our modal
$ionicModal.fromTemplateUrl('new-task.html', function(modal) {
$scope.taskModal = modal;
}, {
scope: $scope
});
$scope.createTask = function(task) {
if(!$scope.activeProject || !task) {
return;
}
console.log($scope.activeProject.task);
$scope.activeProject.task.$add({
title: task.title
});
$scope.taskModal.hide();
// Inefficient, but save all the projects
Projects.save($scope.projects);
task.title = "";
};
$scope.newTask = function() {
$scope.taskModal.show();
};
$scope.closeNewTask = function() {
$scope.taskModal.hide();
};
$scope.toggleProjects = function() {
$scope.sideMenuController.toggleLeft();
};
// Try to create the first project, make sure to defer
// this by using $timeout so everything is initialized
// properly
$timeout(function() {
if($scope.projects.length == 0) {
while(true) {
var projectTitle = prompt('Your first project title:');
if(projectTitle) {
createProject(projectTitle);
break;
}
}
}
});
});
I'm interested in the objects at the bottom
console.log($scope.projects)
Update
After digging around it seems I may be accessing the data incorrectly. https://www.firebase.com/docs/reading-data.html
Here's my new approach
// Load or initialize projects
//$scope.projects = Projects.all();
var projectsUrl = "https://ionic-guide-harry.firebaseio.com/projects";
var projectRef = new Firebase(projectsUrl);
projectRef.on('value', function(snapshot) {
if(snapshot.val() === null) {
console.log('location does not exist');
} else {
console.log(snapshot.val()['-JGTdgGAfq7dqBpSk2ls']);
}
});
$scope.projects = $firebase(projectRef);
$scope.projects.$on("loaded", function() {
// Grab the last active, or the first project
$scope.activeProject = $scope.projects.$child("a");
});
I'm still not sure how to traverse the keys programmatically but I feel I'm getting close
It's an object containing more objects, loop it with for in:
for (var key in $scope.projects) {
if ($scope.projects.hasOwnProperty(key)) {
console.log("The key is: " + key);
console.log("The value is: " + $scope.projects[key]);
}
}
ok so val() returns an object. In order to traverse all the children of projects I do
// Load or initialize projects
//$scope.projects = Projects.all();
var projectsUrl = "https://ionic-guide-harry.firebaseio.com/projects";
var projectRef = new Firebase(projectsUrl);
projectRef.on('value', function(snapshot) {
if(snapshot.val() === null) {
console.log('location does not exist');
} else {
var keys = Object.keys(snapshot.val());
console.log(snapshot.val()[keys[0]]);
}
});
$scope.projects = $firebase(projectRef);
$scope.projects.$on("loaded", function() {
// Grab the last active, or the first project
$scope.activeProject = $scope.projects.$child("a");
});
Note the var keys = Object.keys() gets all the keys at firebaseio.com/projects then you can get the first child by doing snapshot.val()[keys[0])

Resources