Right now, I am able to create objects and save them to a rails database through a json api. It is a simple todo list app that when I add an object, it goes into the todo list above the input fields. I am also able to query all the objects on the index view and list all of my todo objects.
When I click on a checkbox next to each todo item, it is supposed to change it's :done attribute to true, so that I do not show it anymore after they click a "Clear" button which is the clearCompleted function.
Here is my js code
angular.module("Todo", ["ngResource"])
function TodoController($scope, $filter, $resource) {
Todo = $resource("/todos.json", {id: "#id"}, {update: {method: 'PUT'}})
$scope.todos = Todo.query()
$scope.getTotalTodos = function () {
return $scope.todos.length;
};
$scope.clearCompleted = function () {
Todo.save({done:true})
$scope.todos = $filter("filter")($scope.todos, {done:false});
};
$scope.addTodo = function () {
entry = Todo.save({title:$scope.newTodo.title, importance:$scope.newTodo.importance, description:$scope.newTodo.description, done:false})
$scope.todos.push(entry);
$scope.newTodo.title = '';
$scope.newTodo.importance = '';
$scope.newTodo.description = '';
};
}
What is happening is that rather than updating that object in the database, it is creating a brand new todo item and just giving it the attribute of :done => true. It makes sense because in that clearCompleted function it looks like we are creating an object not updating an existing one.
How do I update the record in the database then?
You shouldn't use Todo.save({}) to update a todo. As you said it create a new object.
Write code as follows.
Todo = $resource("/todos.json", {id: "#id"}, {'save': {method: 'PUT'}})
$scope.todos = Todo.query();
var todo = todos[0];//A todo that should be updated
todo.done = true;
todo.$save();
Mabe you need a parameter for todo key in your save url.
using $resource
Related
I'm working with Firebase and AngularJS and I need to delete random generated id in Realtime Database.
var todoFirebaseID;
//add Firebase
$scope.addFirebase = function() {
var objects = {
title: objectTitle.value,
content: objectContent.value
}
var list = $firebaseArray(storageRef);
list.$add(objects).then(function(storageRef) {
todoFirebaseID = storageRef.key;
$scope.addTodo();
});
}
// Remove Firebase
$scope.removeFirebase = function() {
var obj = $firebaseObject(storageRef);
obj.$remove().then(function() {
});
}
I tried it, but it deletes all data in Firebase. I need to delete only the selected data.
Does anyone know how to do it?
You're telling Firebase to remove the entire database, so that's precisely what it does. If you only want to remove a single item, you should invoke $remove() on that specific item.
The only way that I can see deleting an item from the code you shared is:
$scope.removeFirebase = function() {
var obj = $firebaseObject(storageRef.child(todoFirebaseID));
obj.$remove();
}
So we're passing in a reference to the todoFirebaseID child item.
In a more realistic app, you'd trigger a handler when the user clicks the delete button and then that handler would figure out the ID of the item the user clicked on.
Here is the situation. I have a list of games that I am subscribing to and showing to the user. i.e. {_id: '325jfsd3253', gameName: 'shoot2', earnedAchievements: 20} and each game has a list of achievements within another collection i.e. {_id: '324545fe23', gameId: '325jfsd3253', achievementName: 'savior'. I am trying to get the total achievement count without having to subscribe to every achievement record for each game. I am doing this by doing a Meteor.call() to the server within each game template gameTemplate.onCreated function that returns the total achievement count for each game. Currently, I am trying to use a reactive var to set the value that is returned from the meteor call like so.
Template.gameTemplate.onCreated = function() {
//the reactive var is set beforehand. this.data._id is the game id
Meteor.call('getGameCount', this.data._id, function(error, result) {
if (error) return;
reactiveVarForCount = result;
}
}
and then using the reactive var in a helper like so
remainingAchievements: function () {
//the earnedAchievements of the game is within the parent context
var parentData = Template.parentData(1);
var totalAchievements = totalAchievementDependency.get();
if (parentData && totalAchievements) {
return totalAchievements - parentData.earnedAchievements;
}
//return 100;
}
however, the reactive var is reset for each game and so only ends up holding the value of the result of the last game to get counted (the last time the meteor method getGameCount is called).
What would be the best way to attach the result of a meteor method call to the current data context and have it be reactive so that the UI updates when the new data is returned and the helper is re-run.
I actually answered this myself. By placing the reactive var within the onCreated callback and attaching it to the template instance, I was able to scope it correctly and have one reactive var for each instance of the template.
Template.myGame.onCreated = function() {
var self = this;
var self.achiCount = new ReactiveVar();
Meteor.call('getGameCount', self.data._id, function(err, res) {
if (err) return;
self.achiCount.set(res);
});
}
and then you can access the reactive var through the template instance like so:
Template.myGame.helpers({
getCount: function() {
//this will be the reactive var value and will be reactive
return Template.instance().achiCount.get();
}
});
I am learning angularjs.I have created one order List and have delete button in every row. My delete function is working fine,what i need to do to refresh the list after delete success.
this below is my sample code
$scope.deleteFunc = function (id) {
var deleteOrder = $resource('/api/orders/:id', { id: id });
deleteOrder.delete();
Order = $resource("/api/orders")
$scope.Order = Order.query();
};
})
Please suggest the proper way how to refresh the list.
Angular resource requests are asynchronous. So when you do deleteOrder.delete(), the request need time to execute.
So when you do Order.query(), the request of the delete may still be in progress. So your server just give your order again in your list.
You must refresh the list after the end of the delete request.
$scope.deleteFunc = function (id) {
var deleteOrder = $resource('/api/orders/:id', { id: id });
deleteOrder.delete(function() {
// This function will be called at the end of the delete
Order = $resource("/api/orders")
$scope.Order = Order.query();
});
};
I am trying to implement a list-details view. The list is generated with $firebaseArray(ref). When an item on the list is clicked, the list controller uses list.$getRecord(item.$id) to get the particular record. Puts it in a global service(just and empty object with set and get) and in my detail controller i assign that service(already set to the selected item) to a scope variable in the detail controller and display it.
The information in the detail view is editable. and when it is editted, a save button appears which when clicked saves the edit using this code
item = editItem; //editItem contains the new changes made on the detail page
list.$save(item).then(function(ref){
//ref.key() === item.$id; //
console.log("Your Edit has been saved');
});
This works. The edits are reflected on the remote firebase data.
But the problem occurs when i navigate back to the list view and try to click another item. It gets an error which says list.$getRecord() is not a function. Now this error doesn't occur when you don't save an edit on the details view.
I printed out the list array before and after i save and i realised this
List array before an item is saved (contains AngularFire methods)
List array after an item is saved (no longer contains AngularFire methods)
I have no idea why $firebaseArray is reacting this way. Is there something i am missing? is this a normal behaviour?
PS: i am using ionic and angularFire.
I can post more code if neccesary
EDIT
Here is an abstraction of the code
List.html
<ion-list>
<ion-item href="#/lead/info" ng-click="vm.selectItem(l.$id)" ng-repeat="l in vm.list" >
<h3>{{l.firstName}} {{l.lastName}}</h3>
<h4 class="">
<p>{{l.topic}}</p>
</h4>
</ion-item>
</ion-list>
list.js (controller function)
function ListCtrl(selectedItem, $firebaseArray) {
/* jshint validthis: true */
var vm = this;
vm.list= {};
vm.selectItem = selectItem;
loadList(); //Loads the List array
function loadList() {
var fireList = new Firebase("https://xxxxx.firebaseio.com/list");
var r = $firebaseArray(fireList);
r.$loaded(function () {
vm.list = r;
});
console.log(vm.list); //Outputs the first image(above). But after an item edit and i go back, outputs the second image(above)
}
function selectItem(index) {
var sItem = vm.list.$getRecord(index);
selectedItem.setList(vm.list);
selectedItem.setItem(sItem);
}
}
The selectedItem service is simple. i use it to set a single object or array of objects
function selectedItem() {
var sItem = {};
var List = {};
return {
getItem: function () {
return sItem;
},
setItem: function (authObject) {
sItem = authObject;
},
getList: function(){
return List;
},
setList: function(al){
List = al;
}
};
};
The detail view controller is ass so:
item.js(controller function)
function ItemCtrl(selectedItem, $scope, $firebaseObject) {
/* jshint validthis: true */
var vm = this;
$scope.selectedItem = selectedItem.getItem();
$scope.listArray = selectedItem.getList();
//vm.item = $scope.selectedItem;
function saveEdit() {
var t = $scope.selectedItem;
$scope.listArray.$save(t).then(function(ref){
//console.log(ref);
});
}
};
UPDATE
After serious cross checking throughout my code i realised the issue is not from AngularFiire array. Even the workaround i did with the r.$watch and r.$loaded was unnecessary. the need for the work around was cause by another part of my code i didnt think was relevant.
I apologise for the mistake. I'd be deleting this question and a related one soon
Try using a watcher to reload the data:
var fireList = new Firebase("https://xxxxx.firebaseio.com/list");
var r = $firebaseArray(fireList);
r.$watch(function() {
r.$loaded(function () {
vm.list = r;
});
});
This is a common way of dealing with updates in an easy way, might solve your problem.
I'm trying to convert my basic crud operations into an API that multiple components of my application can use.
I have successfully converted all methods, except the update one because it calls for each property on the object to be declared before the put request can be executed.
controller
$scope.update = function(testimonial, id) {
var data = {
name: testimonial.name,
message: testimonial.message
};
dataService.update(uri, data, $scope.id).then(function(response) {
console.log('Successfully updated!');
},
function(error) {
console.log('Error updating.');
});
}
dataService
dataService.update = function(uri, data, id) {
var rest = Restangular.one(uri, id);
angular.forEach(data, function(value, key) {
// needs to be in the format below
// rest.key = data.key
});
// needs to output something like this, depending on what the data is passed
// rest.name = data.name;
// rest.message = data.message;
return rest.put();
}
I tried to describe the problem in the codes comments, but to reiterate I cannot figure out how to generate something like rest.name = data.name; without specifying the name property because the update function shouldn't need to know the object properties.
Here is what the update method looked like before I started trying to make it usable by any of my components (this works)
Testimonial.update = function(testimonial, id) {
var rest = Restangular.one('testimonials', id);
rest.name = testimonial.name;
rest.message = testimonial.message;
return rest.put();
}
How can I recreate this without any specific properties parameters hard-coded in?
Also, my project has included lo-dash, if that helps, I don't know where to start with this problem. Thanks a ton for any advice!
Try like
angular.extend(rest,testimonial)
https://docs.angularjs.org/api/ng/function/angular.extend