2

I'm writing a Single Page App with the help of Angular. My previous experience is just kludged together JavaScript with no strict testing or adherence to models.

I've written a small test app (imagine something much like the yeoman todo app : http://yeoman.io/codelab.html). In said app, if the user tries adding a duplicate entry, I'd like to throw an error.

So on the html file I've got an add button:

<button ng-click="addPerson(newPerson)">Add</button>

This runs the addPerson function in the controller:

$scope.addPerson = function (name) {
        try {
            $scope.awesomePeople = PeopleListService.addPerson(name);
        }
        catch(err) {
            // do something with err
        }
    };

Which in turn runs the appropriate function in the service/factory (which in the future will get it's data from a DB -- this is just a learning process for me):

fact.getPeople = function () {
    return peopleList;
};

fact.addPerson = function(name) {
    if (peopleList.indexOf(name)===-1) {
        peopleList.push(name);
        return fact.getPeople();
    } else {
        throw 'Name (' + name + ') already in awesomePeople list';
    }
};

This all works fine and dandy. (these are just snippets)

I've been taught to throw errors and to catch and handle them gracefully. In this case, I'd like to notify the user that they tried to add a duplicate.

My question is slightly philosophical -- if I display anything in the controller (say, alert(err);, I've violated the MVC model by having the controller directly contact the user - no? This will have coupled the controller to the view/UI - again, something I don't want to do. Is it best to simply re-throw the error from the controller and then catch it in the html/view? If so - is there a good way to do that within an angular expression? Thoughts?

I have looked deeper, using one of the answers below, and found the following link informational: UI Notifications with angular js and might give this angular notifications plugin a try: https://github.com/Swimlane/angular-notifications

Community
  • 1
  • 1
lowcrawler
  • 6,777
  • 9
  • 37
  • 79
  • 1
    MVC is not a strict rule in my opinion, It's just a suggestion or guideline about seperating concerns.. You don't have to be too much worried about `violating the MVC model`. For me I use a notification service, which show dom notifications using some js plugin. I wrapped the plugin's function inside my service and use my service inside controllers. This way I can easily replace the plugin with another one. Hope this helps. – Vignesh May 25 '15 at 11:47

1 Answers1

2

I guess there's multiple ways to achieve this, one could be to define a variable/object above the scope of $scope.addPerson, e.g. hasError and $watch it. A basic approach to do this is given in here: $watch (2nd post)

Another way could be using broadcast/emit & on, where for this particular problem, I'd recommend $watch, since emit/broadcast will 'fire' the event either downwards or upwards the $scope. This might help you there.

Very basic example:

$scope.hasError = '';

$scope.$watch('hasError', function() {
 /* Yourstuff */
});


$scope.addPerson = function (name) {
        try {
            $scope.awesomePeople = PeopleListService.addPerson(name);
        }
        catch(err) {
            $scope.hasError = err;
        }
    };

You might also not use watch but {{hasError || ''}} to display the error, IF this controller is available in the given context.

I've violated the MVC model by having the controller directly contact the user - no? You're using a Service as it seems, Services are meant to enable communication between controllers, so no, using the service itself to create a communication layer does not violate the MVC Model.

This will have coupled the controller to the view/UI - again, something I don't want to do. That is one of angulars main features, you will barely get arround putting this piece into an controller (if you want a specific logic behind it) and binding it to atleast a template in some way (if you want to show it to the user).

Community
  • 1
  • 1
F4b
  • 95
  • 7
  • Where would one place the watch code? The only place I can think that is 'above' the controller code is the main app code... and all that does is configure the dependencies and the routes. If I put it in the controller, I have the same problem I had originally (the controller directly showing things to the user). – lowcrawler May 25 '15 at 14:07
  • I'm not sure if I got you 100%, but if you don't want it in this controller at all you might try injecting the $rootScope, and broadcasting from there to the child controllers where one of the child controllers has to be the desired user controller (if you want clean seperation there). However to do it the 'angularway', you will need a child parent relation of e.g. controllers to do that. You've got 2 official choices then, Shared Services and Events, you can also $watch & $broadcast on a service to 'combine' both. – F4b May 25 '15 at 15:36
  • I think that, perhaps, I didn't explain myself. I don't wan the controller coupled to the UI. As such, I don't want to do an 'alert' out of the controller. It's my understanding that with the MVC model, I should have the controller change the model (to something like 'alert status') and have the view pickup on said change. I'm unsure how to do this --- again, without coupling the UI to the controller or model. – lowcrawler Jun 02 '15 at 19:01