I have a MongoDB document (on MongoLab.com) called client and this is going to be used to track a fitness competition. Each week there will be a "weigh-in" and some other details tracked.
What I'm stuck on is how to add a subdocument to the client document to track the results using AngularJS.
I feel that this may be something obvious and basic that I'm missing, but I haven't figured out how to append a new field to an existing record, array or non-array.
Below is what I believe to be the relevant details, but feel free to ask for more details if appropriate.
Full code is pasted at http://pastebin.com/4tyRiKus
Example client (I can add a client with no trouble)
{
"_id": {
"$oid": "50eee69fe4b0e4c1cf20d116"
},
"firstName": "Jon",
"lastName": "Doe"
}
Now from within a different template that pulls data via the _id (/detail/:cliendId) which works, but I'm looking to add a data point for a weigh-in.
<form ng-submit="addWeighIn()">
<input type="date" ng-model="date" required />
<input type="text" ng-model="weight" placeholder="Weight" smart-float required />
<input type="submit" class="btn btn-primary" value="Add" />
</form>
Clicking the Add button here continues on through the next part.
Function in control to handle (this does fire and calls update() in a MongoLab module)
$scope.addWeighIn = function () {
console.log("addWeighIn: " + $scope.date + " : " + $scope.weight);
// the below line is obviously wrong, just out of ideas.
$scope.client.weights = [ { date: $scope.date, weight: $scope.weight } ];
$scope.client.update(function () {
});
};
The console shows that addWeighIn line and the network data shows that it sends a request, but it doesn't actually have the weight in the document and is the same as above.
MongoLab resource called from $scope.addWeighIn() and fires
Client.prototype.update = function (cb) {
console.log("mongolab: update: " + cb);
return Client.update({ id: this._id.$oid },
angular.extend({}, this, { _id: undefined }), cb);
};
Data sent via update() (missing the new weigh-in data)
{
"_id": {
"$oid": "50eee69fe4b0e4c1cf20d116"
},
"firstName": "Jon",
"lastName": "Doe"
}
This is what I'm looking for, in the actual database but I need to add the weights and believe I'm not understanding something fundamental.
{
"_id": {
"$oid": "50eee69fe4b0e4c1cf20d116"
},
"firstName": "Jon",
"lastName": "Doe"
"weights": [
{ "date": "1/3/2013",
"weight": 155 }
{ "date": "1/10/2013",
"weight": 150 }
]
}
I have a few questions on what to do.
ng-model to client.weights.date? Ex: <input type="date" ng-model="client.weights.date" required /> (Doesn't work, but am seeing if there is a similar way)I've found the $push description at http://docs.mongodb.org/manual/applications/update/ and may be what I need to use, but I'm not certain how to use this the AngularJS way.
I eventually discovered that my issue was with the MongoLab resource.
I swapped my sad implementation with the one found at https://github.com/pkozlowski-opensource/angularjs-mongolab and it worked.
Since I struggled to find an example, here is how to add the subdocuments.
html
<form ng-submit="addWeighIn()">
<table class="table table-striped">
<thead>
<tr>
<th>Date</th>
<th>Weight</th>
<td></td>
</tr>
</thead>
<tbody>
<tr ng-repeat="weight in client.weighIn | orderBy:'date'">
<td>{{weight.date}}</td>
<td>{{weight.weight}}</td>
<td></td>
</tr>
</tbody>
<tfoot>
<tr>
<td>
<input type="text" ng-model="date" placeholder="Date of weigh-in" required />
</td>
<td class="input-append">
<input type="text" ng-model="weight" placeholder="Weight" smart-float required />
<span class="add-on">lbs</span>
</td>
<td><input type="submit" class="btn btn-primary" value="Add" /></td>
</tr>
</tfoot>
</table>
</form>
script
$scope.addWeighIn = function () {
console.log("addWeighIn: " + $scope.date + " : " + $scope.weight);
$weighIn = { date: $scope.date, weight: $scope.weight };
// push to the existing array if it exists
if ($scope.client.weighIn)
$scope.client.weighIn.push($weighIn);
// else create the field if it doesn't exist
else
$scope.client.weighIn = [ $weighIn ];
$scope.client.update(function () {
// do whatever after the update
});
};