4

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.

  1. Can I do this declaratively in the HTML code such as setting 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)
  2. If not declaratively, what is the proper way to do this via AngularJS?
  3. What sort of terminology should I user to find things on this? That seems to be my main frustration, can't find examples.

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.

jared
  • 5,369
  • 2
  • 21
  • 24
Kirk
  • 16,182
  • 20
  • 80
  • 112
  • client.weights is an array therefore you need to do an ng-repeat="weight in client.weights" and bind that variable to ng-model="weight.data" – Liviu T. Jan 10 '13 at 20:16
  • There isn't yet any data in `client.weights`. I'm hoping ro figure out how to actually get the data into the MongoDB document – Kirk Jan 10 '13 at 20:24

1 Answers1

3

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
    });
};
Kirk
  • 16,182
  • 20
  • 80
  • 112