I am a newbie to IonicFrameWork and was following their "starter tab" template and made a few modifications to "delete" and "bookmark" items from a factory.
My books.js which contains the factory looks as follow:
.factory('Books', function() {
// books data
var books = [{
id: 0,
title: 'Sample Title',
author: 'Sample Author',
category: 'Horor, Fiction',
cover: '/cover.jpeg',
details: 'some details about the book',
chapters: [
{
id : 1,
name: 'Chapter 1',
filename: 'chapter1.html',
},
{
id : 2,
name: 'Chapter 2',
filename: 'Chapter2.html',
}
]
}
.....
return {
all: function() {
return books;
},
// remove a book from the list
remove: function(book) {
books.splice(books.indexOf(book), 1);
},
and my controllers.js looks like this:
....
.controller('DashCtrl', function($scope, Books) {
$scope.books = Books.all();
$scope.remove = function(book) {
Books.remove(book);
};
})
.controller('singlebookCtrl', function($scope, $stateParams, Books){
$scope.book = Books.get($stateParams.bookId);
$scope.toggleIcon = function ($evemt, iconName, book){
var buttonClasses = $event.currentTarget.className;
// add the book to favorite
if (....){
book.isFavorite = true;
}
// remove the book from favorite
else {
book.isFavorite = false;
}
....
when I exit the app and open it again, the deleted item is back and favorite items are gone.
When searching for a solution , I came across this article which states I should use window.localstorage. But not sure how I should apply this method for a factory.
I personnaly prefer using ngStorage that makes it very simple and straight forward to use localStorage & sessionStorage.
For example, after injecting the dependency in your controller you can:
Set a variable :
$scope.favList = [1, 4, ...]
$scope.jsonList = { ... }
$localStorage.favLists = $scope.favList;
$localStorage.jsonList = $scope.jsonList;
Access a variable, Simply access to localStorage value :
var favList = $localStorage.favLists;
For all intents and purposes you can treat Local Storage just as if it were a key/value store, like a javascript object. So if you want to save a value in local storage, just do it like the following.
window.localStorage["bookOne"] = "STRING HERE"
Or if you want to save a javascript object:
window.localStorage["bookOne"] = JSON.stringify({a:b})
And it should persist between page reloads.
The real issue here is that in your code, you are setting books on each load with var books = .... Every time you reload the application it will re-apply books and favourites will be lost. So beyond just saving it to window.localStorage you will also have to read from local storage and assign it to your books and favourites variables when your app loads in order to see the changes that were previously made.
You can simply do it with angular-local-storage module, here's some example based on your problem.
angular.module('app', ['LocalStorageModule'])
.factory('Books', function(localStorageService) {
// favorites list(books id)
var favList = [1, 2, 3, ...];
// ....
return {
remove: function(id) {
favList.splice(favList.indexOf(id), 1);
// sync with localStorage
localStorageService.set(favorites, favList);
},
// ....
}
});
Note that you can simply use angular-local-storage#bind and bind specific scope-key to this service that automatically do this synchronisation for you. for example:
// Inside your controller
$scope.favList = [1, 4, ...]
// returns a deregistration function for this listener.
$scope.unbind = localStorageService.bind($scope, 'favList');
Related
I have an app that directs to a custom url based on a given employeeId parameter when a particular employee is clicked on in a list. When the employee is clicked on, you are taken to an employee details page with their id property as a parameter, and I can display this property in the dom.
What I'm trying to do is to display this employee object's other properties in this different state, which I've had a look around at trying to do, but can't find a solution that matches what I'm trying to do.
Example:
Clicking on employee number 21101994 on employees/employeesList state directs to employees/employeeDetails/?21101994 page and displays only their data in the js fields such as {{employee.firstName}}.
I can successfully show the id, but I want to be able to show ALL of the data for the object that matches the employee's id.
The url routing is working fine, and clicking on this employee on the list page directs correctly to a details page with their parameter, but I can't seem to successfully pass their data into the new state/controller.
-
HTML link:
<li class="collection-item col-xs-12" data-ng-repeat="employee in employees | orderBy: sortByAllDepartments | filter:searchAllDepartments">
<a ui-sref="employees/employeeDetails({employeeId: employee.id})" class="employeeLink"></a>
-
What I've tried with the states:
.state('employees/employeesList', {
url: '/employees/employeesList',
templateUrl: 'pages/employees/employeesList.html',
controller: 'employeesListController'
})
.state('employees/employeeDetails', {
url: '/employees/employeeDetails/:employeeId',
templateUrl: 'pages/employees/employeeDetails.html',
resolve: {
employeeId: function($stateParams) {
return $stateParams.employeeId;
}
},
controller: function(employeeId) {
console.log(employeeId)
}
})
-
Employees service:
app.service('employeesService', function() {
var employees = [
{
id: '21101994',
firstName: 'Employee',
lastName: 'One'
}
];
var addEmployee = function(newObj) {
employees.push(newObj);
};
var getEmployees = function() {
return employees;
}
return {
addEmployee: addEmployee,
getEmployees: getEmployees
}
})
-
Employees List Controller:
app.controller('employeesListController', function($scope, $stateParams, employeesService) {
$scope.active = 'active';
$scope.sortByAllDepartments = '+lastName';
$scope.employees = employeesService.getEmployees();
})
The states will be receiving params like
url: '/employees/employeeDetails/{:employeeId}',
Or
url: '',
params: {
employeeId: null
},
resolve: {...}
I prefer the second one to receive due to clarity.
To pass all the data of employee, localstorage of employee object will be better in case you need this object frequently or in other parts in application.
localStorage.setItem('employeeData', JSON.stringify(empData));
To access this you can do
let empData = JSON.parse(localstorage.employeeData); //Object
In case you need to need this stored data, let's say you are navigating away from this employeeDetails state, you can delete this
localstorage.removeitem('employeeData');
If you require passing multiple state params, just add a comma separated string
ui-sref="employeeDetails({id: emp_id, name: emp_name, mobile: emp_mobile})"
and then receive this in state as below
params: {
employeeId: null,
employeeName: null,
employeeMobile: null
},
I hope this last makes clear as in why should you avoid passing too many params in stateParams
Hello I am developing an Ionic app and I have an array that I want to push items on to it, but not lose the data when I change screens. Also, I do not want to use a database. Is there any other way? to add to an existing array and store that array locally?
$scope.tasksCollection = [
{ info: 'Go studying', measured: 'no', total: 1, done: 1, id: 1 },
{ info: 'Go to the beach', measured: 'no', total: 1, done: 1, id: 2},
{ info: 'Run', measured: 'yes', total: 30, done: 15, id: 3}
];
$scope.tasksCollection.push({
info: $scope.taskInfo,
measured: $scope.result,
total: total,
done: 0,
id: $scope.tasksCollection.length
})
The add function is working perfectly I just loose the data when changing states.
If you want to keep data between controllers either use a service or local storage if you want to keep the data even when you quit the app.
Service example
Further angular documentation regarding services: https://docs.angularjs.org/guide/services
service.js:
angular.module('yourmodule.services')
.service('Tasks', [function () {
var collection = {
tasks: []
};
return {
getTasks : function(){ return collection.tasks; }
}
}]
);
controller.js
angular.module('yourmodule.controllers')
.controller('TaskCtrl', ['$scope', 'Tasks',
function($scope, Tasks){
$scope.Tasks = Tasks //Expose service to template
$scope.addTask = function(){
Tasks.getTasks().push({name : 'a new task'});
}
}]);
Local storage example
This is an excellent library which provides easy localstorage access for angularjs: https://github.com/grevory/angular-local-storage
angular.module('yourmodule.controllers')
.controller('TaskCtrl', ['$scope', 'localStorageService',
function($scope, localStorageService){
$scope.collection = {
tasks : localStorageService.get('tasks') || [];
}
$scope.addTask = function(){
$scope.collection.tasks.push({name : 'a new task'});
localStorageService.set('tasks', $scope.collection.tasks);
}
}]);
How about HTML5's locaStorage?
See Ionic formulas on Using Local Storage.
I have a factory, which goes into a controller, and I am trying to get data from that display on an HTML page. I am having trouble specifying an Object's pathway however.
My Factory:
app.factory('APIMethodService', function() {
var Head = "api.example.com";
return {
apis:
[{
accounts: [
{
v1: [
{
uri: Head+"/v1/accounts/",
item1: "AccountNumber",
item2: "MoneyInAccount"
}],
v2: [
{
uri: Head+"/v2/accounts/",
item1: "AccountNumber",
item2: "MoneyInAccount"
}]
}
],
customers: [
{
v1: [
{
uri: Head+"/v1/customers/",
item1: "CustomerName",
item2: "CustomerID",
item3: "CustomerEmail"
}]
}
]
}]
};
});
My Controller:
app.controller('APIController', function($scope, APIMethodService) {
$scope.title = "API";
$scope.apiList = APIMethodService;
$scope.accountList = $scope.apiList.accounts.v1;
$scope.accountList2 = $scope.apiList[0][0];
});
My HTML
<div ng-controller="APIController">
<div id="api" class="row">
<div class="col-xs-12">
<div class="row" style="font-size:20px">
{{title}} Page!
<table class="table table-striped">
<tr ng-repeat="api in apiList | orderBy:'uri' | filter:search">
<td>{{api.uri}}</td>
<td>{{api.item1}}</td>
<td>{{api.item2}}</td>
</tr>
</table>
</div>
</div>
</div>
</div>
The errors I get are in regards to the Controller trying to parse out the individual objects I wish to grab, like accounts or customers, and then any version v#, they may have.
So it will say something such as
TypeError: Cannot read property 'v1' of undefined
I just need some help specifying the proper pathways into my factory service.
You have a few problems. First, you are referring to the object returned from the factory incorrectly. APIMethodService is the factory that you're injecting, so you need to first reference the object that that factory is returning like this:
APIMethodService.apis
This will give you your entire JSON object.
From there, the rest of your object is made up of arrays of objects, so referring to 'v1' won't do you any good. You need to specify an index instead. If you want v1, you'll need:
APIMethodService.apis[0].accounts[0].v1
This will give you the v1 array, which again is an array of objects.
Customers would be:
APIMethodService.apis[0].customers[0].v1
The first problem you have is that the factory returns an object with a single property called apis. So basically this $scope.apiList.accounts.v1 should be $scope.apiList.apis.accounts.v1. Bu that's not all as this won't either work since dotting(.) into apis is an array you'd have to use the index. In this case it would be $scope.apiList.apis[0] and then you could .accounts[0].v1 which is also an array containing a single object.
Now if you can I would suggest to you that you'd change how you represent this data structure.
This is how you could do it.
app.factory('APIMethodService', function() {
var Head = "api.example.com";
return {
accounts: {
v1: {
uri: Head+"/v1/accounts/",
items: ["AccountNumber","MoneyInAccount"]
},
v2: {
... // skipped for brevity
}
},
customer: {
... // code skipped for brevity
}
};
});
And then it's just a matter of dotting into your APIMethodService-object like APIMethodService.accounts.v1.items[0] if you want the AccountNumber method name.
Constructing your url could then be done like this.
var baseUrl = APIMethodService.accounts.v1.uri; // 'api.example.com'
var url = baseUrl + APIMethodService.accounts.v1.items[0]; // 'AccountNumber'
// url = "api.example.com/v1/accounts/AccountNumber"
Again, this is one way you could do it but this can be further enhanced upon. The examples I provided are simply for demo purposes and this is not in any way the only way to do it.
Expanding upon recieved comments/questions your service (and data representation) could now look like this.
app.factory('APIMethodService', function() {
var Head = "api.example.com";
return {
accounts: {
v1: {
uri: Head+"/v1/accounts/",
items: [
{
name:'AccountNumber',
description:'Show the account number'
},
{
name:'AccountOwner',
description:'Show information about the owner of the account'
},
{
name:'MoneyInAccount',
description:'Show money in the Account'
}
]
},
v2: {
... // skipped for brevity
}
},
customer: {
... // code skipped for brevity
}
};
});
// Get descriptions
var accountNumberDescription = APIMethodService.accounts.v1.items[0].description; // 'Show the account number'
var accountOwnerDescription = APIMethodService.accounts.v1.items[1].description; // 'Show information about the owner of the account'
var moneyInAccountDescription = APIMethodService.accounts.v1.items[2].description; // 'Show money in the Account'
By using objects with properties like this it's alot easier to understand what you are trying to do. With arrays with indexes you'd have to know or take a look at the source to see what's going on. Here, someone viewing your code they can instantly understand that it is the description you are getting.
My goal is to create a service appointment record associated with multiple resources.
For this purpose I have followed this MSDN example.
The problem rises when I try to associate multiple resources for one particular service appointment, CRM server will store only the last one(1 record). Following demonstrates my code:
//attendees =[... array of resource ids]
var serviceAppointment = {
ScheduledStart: new Date("12/22/2014 4:53 PM"),
ScheduledEnd: new Date("12/22/2014 5:53 PM"),
Subject: "test service",
ServiceId:
{
//// hardcoded id for simplicity
Id: "6f795012-ca55-e411-aa38-00155d0a0948",
LogicalName: "service"
}
};
SDK.JQuery.createRecord(serviceAppointment,"ServiceAppointment"
,function(sa){
for(var i=0;i<attendees.length;i++)
{
var activityParty = {
PartyId:
{
Id: attendees[i],
LogicalName: "systemuser",
},
ActivityId:
{
Id: sa.ActivityId,
LogicalName: "serviceappointment",
},
ParticipationTypeMask:
{
//See http://msdn.microsoft.com/en-us/library/gg328549.aspx
//10 is for resource
Value: 10
}
};
SDK.JQuery.createRecord(activityParty,"ActivityParty", function(ap){debugger;},errorHandler);
}
}
,errorHandler);
As far as I debugged the code the create record is being executed properly without no exception. I believe I'm missing a configuration flag somewhere in my code and CRM is considering one to one association rather than one to many.
Any clues?
I could solve this issue by passing array of parties in service appointment record at the first place rather than inserting them one-by-one at the end. Here is the code which works:
var parties =[];
for(var i=0;i< e.event.attendees.length;i++)
{
var activityParty = {
PartyId:
{
Id: e.event.attendees[i],
LogicalName: "systemuser",
},
ParticipationTypeMask:
{
//See http://msdn.microsoft.com/en-us/library/gg328549.aspx
//10 is for resource
Value: 10
}
}
parties.push(activityParty);
}
var serviceAppointment = {
ScheduledStart: e.event.start,
ScheduledEnd: e.event.end,
Subject: e.event.title,
ServiceId:
{
Id: "6f795012-ca55-e411-aa38-00155d0a0948",
LogicalName: "service"
},
serviceappointment_activity_parties: parties,
};
SDK.JQuery.createRecord(serviceAppointment,"ServiceAppointment"
,function(sa){
debugger;
e.event.ActivityId = serviceAppointmentActivityId = sa.ActivityId;
}
,errorHandler);
}
hope it helps somebody out there.
I'm trying to get a handle on using $resource in angularjs and I keep referencing this answer AngularJS $resource RESTful example for good examples. Fetching a record and creating a record work fine, but now i'm trying to add a "section" to an existing mongo record but can't figure it out.
documents collection
{
_id: 'theid',
name: 'My name",
sections: [
{
title: 'First title'
},
{
title: 'Second title'
}
]
}
angular controller snippet
var document = documentService.get({_id: 'theid'});
// TRYING TO ADD $scope.section TO THE SECTIONS ARRAY IN THE VARIABLE document.
//document.sections.push($scope.section); <-- This does NOT work
//document.new_section($scope.section); <-- could do this and then parse it out and insert it in my backend code, but this solution seems hacky and terrible to me.
document.$save(function(section) {
//$scope.document.push(section);
});
documentService
return $resource(SETTINGS.base + '/documents/:id', { id: '#id' },
{
update: { method: 'PUT' }
});
From the link i posted above, If I was just updating the name field, I could just do something like this:
var document = documentService.get({_id: 'theid'});
document.name = "My new name";
document.$save(function(section) {
//$scope.document.push(section);
});
I'm just trying to add an object to a nested array of objects.
Try this:
documentService.get({_id: 'theid'}, function(document) {
document.sections.push($scope.section);
document.$save();
});