0

Let say there is some data of students that are in classes (groups) of different schools:

{
  "students": {
    "alexa" : {
      "firstName" : "ReJina",
      "grade" : 2,
      "lastName" : "idk",
      ...
    },
    "bobby" : { ... },
    "chris" : { ... },
    ...
  },
  "schools": {
    "springfield" : {
      "name" : "Springfield Elementary",
      "location" : "123 Main St",
      ...
    },
    "quahog" : { ... },
    "zion" : { ... },
    ...
  },
  "group": {
    "one" : {
      "members" : {
        "alexa" : true,
        "bobby" : true,
        "chris" : true
      },
      "school" : {
        "springfield" : true
      },
      "name" : "Math Class"
    },
    "two" : {
      "members" : {
        "bart" : true,
        "lisa" : true,
        "meg" : true,
        ...
      },
      "school" : {
        "quahog" : true
      },
      "name" : "Art Class"
    },
    "three" : { ... },
    "four" : { ... },
    ...
  }
}

To my knowledge this is the proper way of structuring data in a flat way. Please let me know if this is incorrect. I keep the associated lists on each item, so each class needs a roster (members) and if I also had the situation where a student was in more than one class (group) or school, those would need lists of classes and schools they attend.

Now in the HTML we need to have a view that shows all of the schools classes (groups) and the students in each class and the students in the same view with a nested ng-repeat:

<div id="data-table-div" class="col-md-6">
  // Get all the groups, and show them one by one
  <div ng-repeat="group in groups">
    // This works  -  How do I get the school it is associated to?
    //                ??
    {{group.name}} - {{group's school's name}}

    //Start a table
    <table>
      <thead> <tr> <th>Student Name</th> <th>Grade</th> ... </thead>
      <tbody>
        // Get the students in each group, and show them one by one
        //                        ??
        <tr ng-repeat="student in groups.members">
          <td>{{student.name}}</td> <td>{{student.grade}}</td> ...
        </tr>
      </tbody>
    </table>
  </div>
</div>

And in the controller :

angular.module('sofDataViewerApp')
  .controller('dataTableController', function ($scope, $firebaseObject, $firebaseArray) {
    // This gets all of our groups.  It also allows `group.memebers` to render the appropriate number of `<tr>`s as it knows it has N students.
    var groupsRef = new Firebase("https://sof-data.firebaseio.com/studyGroups");
    $scope.groups = $firebaseArray(groupsRef);

    // This will give all the students. How do I get just the template's `group.members` to be each appropriate student?
    var studentsRef = new Firebase("https://sof-data.firebaseio.com/students");
    $scope.allStudents = $firebaseArray(studentsRef);
  });

Question:
How do I get the HTML template to properly iterate over the groups' members and I have access to all of the data of each student (such as their firstName and grade)? (I am assuming it may involve better code in the controller and possibly in the HTML)

PLNKR: http://plnkr.co/edit/uAn1Ky9v5NHHDFPs2c6S?p=preview (If you know how to inject Firebase and angularFire in the plnkr, then it should work, but I still can't figure that out despite including the CDN of them...)

The closest explanation I can understand is on this page by Firebase, they suggest using a LINK_ID, but it is not described as what they mean, esp since they talk about not searching by id. In my case, a link would be synonymous with group and a comment would be a student.

    var commentsRef = new Firebase("https://awesome.firebaseio-demo.com/comments");
    var linkRef = new Firebase("https://awesome.firebaseio-demo.com/links");
    var linkCommentsRef = linkRef.child(LINK_ID).child("comments");
    linkCommentsRef.on("child_added", function(snap) {
      commentsRef.child(snap.key()).once("value", function() {
        // Render the comment on the link page.
      });
    });
chris Frisina
  • 19,086
  • 22
  • 87
  • 167

1 Answers1

1

It looks like you're trying to join multiple "tables". The best way to do that with AngularFire is by extending $firebaseArray (link to docs). With this you can load the additional data from the other locations as each child get added (or is modified).

Also see this answer from Kato that show extending an array (although for a different use-case).

Finally you can consider duplicating the data that is necessary for each screen into the list for that screen. While Firebase is pretty fast to retrieve joined data (it keeps an open connection and can pipeline multiple requests), it will always be faster if you have to do fewer requests to get the data.

An example of this would be if you want to display a list of the members in a group:

"group": {
    "one" : {
      "members" : {
        "alexa" : "ReJina",
        "bobby" : "Robert",
        "chris" : "Christian"
        ...

So instead of just storing true, we actually store the first name of each member here. This allows us to get all the data to show the group members with a single read operation:

ref.child('group/one/members').on('value'...

Then when the user clicks on one of the group members, we'd go to that group member's page and load the data from /students/$studentid and possible have the groups that they're part of (and the names of those groups) under there too..

Community
  • 1
  • 1
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807