mercredi 8 juin 2016

Polymorphic directives in AngularJs


This is a short write up on how to perform ReplaceConditionalWithPolymorphism for directives in angular

Recently I had to add some functionality to a menu-bar that handles navigation between different screens. It is implemented as a directive. The problem was the same directive was instantiated by several controllers, and from some controllers it needs an instance of something, lets call it Book, and from one other controller it needs an instance something else that we’ll call Page.

I’m going to use the syntax of javascript classes to explain the problem, as it is rather clear and not specific to a framework. At the end we’ll look at the angular version.

class MenuBar {
     constructor(book, page) {
          // either of book or page are undefined
     }

     goToView(viewItem) {
    if (onBookView()) {   // i.e. page == undefined
        handleRedirectionFromBookViewTo(viewItem)
    } else // on page view
        handleRedirectionFromPageViewTo(viewItem)
    }
}

}

It is awkward and subject to error to allow either book or page to be null/undefined as it is difficult for another developer to know what is a valid way of instantiating it. Can both be undefined? If I define page, to I have to provide book? As far as testing goes, we have little confidence that it is instantiated with the right arguments in every view, so we're kind of forced to test all functionality in every view to be sure we don’t get a runtime failure. A combinatorial problem.

In addition much of the cyclomatic complexity of this class is unnecessary. Basically one set of branches are used when we have a book and a completely different one when we have a page. This is a clear cut for polymorphism :

class MenuBarForBook {
     constructor(book) {...}
    
     goToView(viewItem) {
    handleRedirectionFromBookViewTo(viewItem)
     }

}

class  MenuBarForPage {
     constructor(page) {...}

     goToView(viewItem) {
     handleRedirectionFromPageViewTo(viewItem)
     }
}

With this design it is unlikely that a constructor won't be called with the right arguments. The combinatorial problem is solved and we've lowered the testing burden.

So how can we do this in angular. Easy; create two different directives that expose the same functions and use the same template.

angular.module('menuBar', [])
    .directive('menuBarBook', [
    function () {
        return {
            templateUrl'src/menu/MenuBar.html',
            scope: {
                book‘=‘    // constructor argument
            },
            linkfunction ($scope) {
                $scope.goToView function () {    // function goToView()
                    handleRedirectionFromBookViewTo(viewItem)
                }
            }
        }
    }])
    .directive('menuBarPage', [
    function () {
        return {
            templateUrl'src/menu/MenuBar.html',
            scope: {
                page'=',
            },
            linkfunction($scope) {
                $scope.goToView function () {
                    handleRedirectionFromPageViewTo(viewItem)
                }
            }
        }
    }])

Conclusion

Polymorphism is a powerful tool both for making the code more usable to other developers by making it more explicit how to use a piece of code. Also, removing if-statements not only makes the code simpler but also makes the tests simpler. I just discovered this could be done with directives without too much overhead. It is worth naming directive inheritance here. However to my understanding it solves a different problem, namely sharing code.

14 commentaires:

  1. Thanks for Sharing This Article.It is very so much valuable content. I hope these Commenting lists will help to my website
    angular js online training
    best angular js online training
    top angular js online training

    RépondreSupprimer
  2. It s a very useful page. Thank you. 16913ec96b9cdabef1198d04b0f42eb3
    goynuk
    sinanpasa
    bafra
    bayat
    aydin
    sultanhisar
    duzici
    beylikduzu
    kuluncak

    RépondreSupprimer
  3. Congratulations on your article, it was very helpful and successful. 5880f1f38a75eb4b58ab63a87a1844d7
    numara onay
    website kurma
    sms onay

    RépondreSupprimer
  4. Thank you for your explanation, very good content. 034d66dc7c7cb0625776d74708618132
    altın dedektörü

    RépondreSupprimer