Looking for guidance working with AngularJS and a large relational database

1,406 views
Skip to first unread message

Patrick Catanzariti

unread,
Aug 6, 2013, 12:00:03 AM8/6/13
to ang...@googlegroups.com
I'm developing my first ever AngularJS app and have been loving it! However, my app is getting a bit more complicated than my initial prototype and I'm unsure if I'm approaching it the correct way. I'd love some guidance on what more experienced AngularJS developers would do. All assistance greatly appreciated!

I have an app in which I have a large amount of data stored in a relational database with many tables all linked together. When I retrieve data from the database, I've got a REST API for the app which returns one JSON object joining several tables together from my database.

For example, I make a call to the server and Angular then receives JSON objects like:
[ { 
    item_id: 1,
    item_name: 'Monkey',
    item_action: 'Eats a banana',
    group_id: 1,
    group_name: 'Primates',
    collection_id: 1,
    collection_name: 'Animals'
} ]

I then output the data in groups like so:
<h1>Animals</h1>
<div class="group">
    <h2>Primates</h2>
    <div class="items">
            <div class="item">
                    <p>Monkey - eats a banana</p>
                    <p>Gorilla - bangs his chest</p>
            </div>
    </div>
</div>
<div class="group">
    <h2>Fish</h2>
    <div class="items">
            <div class="item">
                    <p>Salmon - sings Sinatra songs</p>
            </div>
    </div>
</div>
<div class="group">
    <h2>Insects</h2>
    <div class="items">
            <div class="item">
                    <p>Ant - Forages for food</p>
            </div>
    </div>
</div>
I managed to get this working with a bit of help from Stack Overflow who pointed me to a solution which uses $.defer to retrieve unique groups from the data. I go through the JSON object of everything, find the unique groups in the data using JavaScript, store them as separate lists and then use them to display data filtered to each list item - http://stackoverflow.com/questions/14800862/how-can-i-group-data-with-an-angular-filter

This all worked, however I've come into issues when trying to set it up so that I can add new groups and collections of information. In these cases, I'm not sure of what best practice would be. If I want to add in a new type of animal, I can add it to my database, however the only way I've managed to get it to synchronise the change automatically in AngularJS has been to pass it in as a JSON object with most values passed as null:
[ { 
    item_id: null,
    item_name: null,
    item_action: null,
    group_id: 4,
    group_name: 'New Group To Add',
    collection_id: 1,
    collection_name: 'Animals'
} ]

This way, it sees the new item and updates the view to show the new group. However, this only seems to work if every single field is passed in. If I've missed a value, e.g. if "item_name" is missing, then AngularJS doesn't seem to update the view. It doesn't seem to see the object the same way as the others? This gets difficult as it means working out ways to get my backend to return null values for tables which I otherwise wouldn't be affecting in these operations (e.g. adding a group doesn't affect the item table, only the table with groups, so it feels a bit hacky to need to retrieve the fields from the item table to get this to work).

Is there a better way to do this in Angular? To have data stored in multiple tables on the database end, represent it cleanly on the Angular side grouped as shown above and show changes to both groups and collections instantly using AngularJS?

Surely there's a nicer way!
Patrick

Daniel Tabuenca

unread,
Aug 6, 2013, 2:39:35 AM8/6/13
to ang...@googlegroups.com
The one advice I give people new to MVCC frameworks, is to not try to bind directly to the domain data, but rather to create a model that more closely matches your view requirements and then transform your domain model into the model before binding (not by trying to do weird gymnastics with filters).

For example in your case, your html looks like a nested list (first a list of groups and within each group the lists of animals in that group). So the easiest model for this would be something that looks like:

[  { group_name: 'Fish', 
     members: [ {  item_name: 'Salmon', item_action: 'Something fishy'}]
    },
    { group_name: 'Primates', 
     members: [ {  item_name: 'Monkey', item_action: 'Eats Bannana''}, { item_name: 'Gorilla', item_action: 'Pounds chest']
    }
]

Then you could easily model this in your html with two nested repeaters (no filters, no weird deferred constructs, just pretty straight-forward iteration)

When you get your animals from the server, rather than just setting whatever you got from the server directly to the scope,  you do something like:


$scope.animals =  createAnimalsByGroupViewModel( animalListFromServer);

Sure,  you'll have to write some code to do the translation (but you are doing that anyways in your filters), Libraries like underscore can make this pretty easy for you. For example, going from your model to the model I suggested would be as easy as:

function createAnimalsByGroupViewModel(animalListFromServer){
   var animalsByGroup = _groupBy(animalListFromServer, 'group_name');
   return _.map(animalsByGroup, function(value, key){ return {group_name: key, members: value}})
}

If you add an animal group on the server and the server returns just a group_name you would take that and just add it to the model:


$scope.animals.push( {group_name: groupNameFromServer, members: []});

Patrick Catanzariti

unread,
Aug 6, 2013, 2:52:27 AM8/6/13
to ang...@googlegroups.com

Thanks Daniel! That's actually incredibly good advice. Simplifies the process dramatically. I'm new to it so guidance like that is exactly what I needed.

I'm going to start to redesign my Angular code with that approach in mind and see if that starts to improve things :)

--
You received this message because you are subscribed to a topic in the Google Groups "AngularJS" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/angular/8FFkOeDuvg4/unsubscribe.
To unsubscribe from this group and all its topics, send an email to angular+u...@googlegroups.com.
To post to this group, send email to ang...@googlegroups.com.
Visit this group at http://groups.google.com/group/angular.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

erwin

unread,
Aug 6, 2013, 7:15:29 AM8/6/13
to ang...@googlegroups.com
Thats some very good advice from Daniel, I sorta do the exact same thing having `Models` come from the back end which i then map or compose into `ViewModels` for views/templates to bind to. It is a level of indirection that should be weighed though, since it does add overhead to the design but as long as you or your team is consistent it turns out to be a good pattern to use.

Luke Kende

unread,
Aug 6, 2013, 11:27:36 AM8/6/13
to ang...@googlegroups.com
I started to answer your post last night and saw that Daniel beat me to it, almost the exact advice I would give.  Underscorejs will make reforming your data into a model easier.  If you are using a RESTful api I might recommend using angular's $resource object if you haven't checked it out yet.  Since you need to transform your data first into a model, you cannot bind the $resource result directly to the scope, but do it on the success callback:

$scope.animalModel = {};

var my_api = $resource('/api/url');

my_api.get({type: 'animals'}, function success(data){
   //transform data here then attach to scope - in reality you might have a lot more transforming to do
   $scope.animalModel = _.groupBy(data,'group_name')
})

Angular has a learning curve and there's no 'standard' solution to each developer's issues.  That kind of makes it fun and creative once you being to understand the tools it gives you.  Good luck.  

Phil

unread,
Aug 6, 2013, 12:04:21 PM8/6/13
to ang...@googlegroups.com
Very helpful post! Are you using underscore for templates as well or just to leverage _groupBy and _.map? How would you display this data using the nested repeaters? 

Patrick Catanzariti

unread,
Aug 16, 2013, 4:36:30 AM8/16/13
to ang...@googlegroups.com
Just wanted to post a follow up, firstly to say thank you! The discussion allowed me to get my app progressing a lot nicer :)

To answer one of Phil's questions, the way I ended up using nested repeaters was like this:
<div class="group" ng-repeat="group in animalGroups">
<h1>{{group.group_name}}</h1>
<div class="animal" ng-repeat="member in group.members | filter:filterNullGroups">
<h2>{{member.item_name}}</h2>
<p>{{member.item_action}}</p>
</div>
</div>

I did end up needing to create a filter to not display values including "null" that my database would return in my JSON data.

Overall, much easier than my previous approach. Really valuable lesson learnt here in how to approach this sort of app structure :)

Patrick
Reply all
Reply to author
Forward
0 new messages