Code Review Stack Exchange is a question and answer site for peer programmer code reviews. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I am a newly developer in angular. I want to do some homework to create forms with Angular. I spent nearly a week to do it, but my teacher was not really satisfied about it. I tried to follow some web tutorials and I thought that it was good but apparently, the quality of my code is very bad (according to the teacher).

I have also another problem due to the fact that my code is compatible with IE8 and has to be compatible with IE11 or Chrome. But for the moment, it's not really the priority. My priority is improving the quality of my code.

(function () {
'use strict';

 // @module UploadDoc Feature
 // @description Definition of 'UploadDoc' module

 // Main controller
uploadDocFeature.controller('client.features.uploadDoc.Controller', [
    '$scope',
    '$http',
    '$parse',
    '$translate',
    '$timeout',
    'client.features.common.DataService',
    'client.features.login.SessionService',
    '$modalInstance',
    function ($scope, $http, $parse, $translate, $timeout, dataService, session, $modalInstance,ezBus) {
        var vm = this;
        // Const
        $scope.docCategory = "pdm_legal_document";

        // Declare an object for all select input, since if you use ng model, it will set its own scope (a child scope of our page)
        $scope.selected  = {};
        $scope.dateErrors = [];
        $scope.doc_classes = [];
        $scope.doc_types = [];
        $scope.context_input = '';
        vm.mapContextClassType = {};

        // Define all functions
        $scope.resetValidate = function () {
            $scope.form_invalid_file_required_4ie = false;
            $scope.form_invalid_4ie = false;
            $scope.form_invalid_context = false;
            $scope.context_hasResult = undefined;
            $scope.context_selected = undefined;
            $scope.dateErrors = [];
            dataService.failed = false;
            dataService.errMsg = '';
        };

        $scope.initDropDownList = function () {

            dataService.initDDL_formatChannel().then(function (result) {
                if (!vm.loadFailed(dataService)){
                    $scope.doc_channels = result["loadChannels"];
                    $scope.doc_formats =  result["loadFormats"];
                }
            });
            vm.loadContextClassType();

        };

        vm.loadContextClassType = function(){
            dataService.initDocClassType("loadAllClassType").then(function (result) {
                if (!vm.loadFailed(dataService)){
                    vm.mapContextClassType = result["loadAllClassType"];
                }
            });
        };

        $scope.validateSelection = function(){
            if(!$scope.context_input){
                vm.reInitContext();
            }
        };

        $scope.$watch("context_input", function(newValue){
            if(!newValue || newValue == ''){
                vm.reInitContext();
            }
        });

        $scope.updateDDL_DocClass = function (contextSelected) {
            $scope.doc_classes = [];
            $scope.doc_types = [];
            if(!vm.mapContextClassType){
                vm.loadContextClassType();
            }
            if(vm.mapContextClassType){
                var mapClass2Type = vm.mapContextClassType[contextSelected];
                for(var oneClass in mapClass2Type) {
                    var oneOption = {
                        label: $translate.instant('i18nClass.' +oneClass),
                        value: oneClass
                    };
                    $scope.doc_classes.push(oneOption);
                }
            }
        };

        $scope.onSelectClass = function (contextSelected, classSelected) {
            $scope.doc_types = [];
            if(!vm.mapContextClassType){
                vm.loadContextClassType();
            }
            if(vm.mapContextClassType){
                var listType = vm.mapContextClassType[contextSelected][classSelected];
                for (var i = 0; i < listType.length; i++) {
                    var oneType = listType[i];
                    var oneOption = {
                        label: $translate.instant('i18nType.' +oneType),
                        value: oneType
                    };
                    $scope.doc_types.push(oneOption);
                }
            }
        };

        $scope.clear = function () {
            // Reset Form
            var ele = document.getElementById("uploadForm");
            if (!(ele === undefined) && ele != null) {
                ele.reset();
            }
            $scope.finished = false;
            $scope.failed = false;

            $scope.resetValidate();
        };

        $scope.cancel= function(){
            $modalInstance.dismiss('cancel');
        };

        vm.loadFailed = function (dataService) {
            if (dataService.failed) {
                $scope.failed = true;
                $scope.errMsg = dataService.errMsg;
                return true;
            }
            return false;
        };

        //-------------- Context Search Functions------------------------

        $scope.onSelectValue = function (item, model, label) {
            if (angular.isObject(item)) {
                $scope.context_name = item.context_name;
                $scope.context_id = item.context_id;

                $scope.context_selected = true;

                $scope.updateDDL_DocClass("pdm_" + $scope.context_name);
            }
        };

        /**
         *   typeahead-editable="false" -> ngModel is set only the value is selected from the typeahead list
         */
        $scope.checkContext = function () {
            if ($scope.context_hasResult && !$scope.context_selected) {
                //Search has result, but not selected
                $scope.form_invalid_context = true;
                return false;
            } else if ($scope.context_hasResult == false) {
                $scope.form_invalid_context = true;
                return false;
            }
            $scope.form_invalid_context = false;
            return true;
        };

        vm.reInitContext = function (){
            $scope.context_selected = false;
            $scope.selected.doc_class = '';
            $scope.selected.doc_type = '';
            $scope.doc_classes = [];
            $scope.doc_types = [];
        }


        /**
         * method for the auto suggestion in dropdownlist
         * @param inputValue
         * @returns {*}
         */
        $scope.doAutoSearch = function (inputValue) {
            vm.reInitContext();
            if (typeof inputValue !== 'undefined' && inputValue.length > 0) {
                var url = './srv/navbarSearchServlet';
                var dataObj = {
                    "context_id": inputValue,
                    "context_name":["pdm_person","pdm_root","pdm_business_partner"],
                    "token": session.getTicket()
                };

                var headers = {"headers": {"Content-Type": "application/json; charset=UTF-8"}};
                //the first method in the then is for success the second for error
                return $http.post(url, dataObj, headers).then(function (response) {
                    var arrayObjects = [];
                    //test the status
                    if (response.status === 200) {
                        var results = response.data;
                        //iterate on the object of the results list : object ={context_id:value,context_name:<person or root>}
                        angular.forEach(results, function (object) {
                            //translate the context_name
                            var i18nName = 'i18nNavbarSearch.' + object.context_name;
                            var valueTranslated = $translate.instant(i18nName);
                            //add the display value to the object returned
                            object.display = object.context_id + ' - ' + valueTranslated;
                            this.push(object);
                        }, arrayObjects);
                    }

                    $scope.context_hasResult = arrayObjects.length > 0;

                    return arrayObjects;
                }, function (response) {
                    alert('An error occurred during the process,try again. If the problem persist, contact support team.');
                    return {};
                });
            }
        };
        //-------------- End Context Search Functions------------------------

        //-------------- Submit Functions------------------------

        $scope.uploadDoc_submit4IE = function () {
            if (uploadDoc_formValidate()) {
                //Use more basic js to submit
                document.getElementById("uploadForm").submit();
            }
        };

        window.uploadDoc_formValidate = function () {
            var rt = true;
            if ($scope.form_invalid_context)
                rt = false;

            if($scope.dateErrors.length > 0) {
                rt = false;
            }

            if (!(window.isIE10UP === undefined) && !window.isIE10UP) {
                $scope.form_validation_msg_4ie = "";
                $scope.form_invalid_4ie = false;
                $scope.form_invalid_file_required_4ie = false;

                // Just for IE Check, other browser should support HTML5 'required' property
                if ($("#fileToUpload").val() == '') {
                    $scope.form_invalid_file_required_4ie = true;
                    rt = false;
                }
                if ($("#context").val() == '') {
                    $scope.form_invalid_4ie = true;
                    $scope.form_validation_msg_4ie = $scope.form_validation_msg_4ie + " " + $translate.instant('i18nUploadDoc.lbl_context');
                    rt = false;
                }
                if ($("#doc_class").val() == '') {
                    $scope.form_invalid_4ie = true;
                    $scope.form_validation_msg_4ie = $scope.form_validation_msg_4ie + " " + $translate.instant('i18nUploadDoc.lbl_docClass');
                    rt = false;
                }
                if ($("#doc_type").val() == '') {
                    $scope.form_invalid_4ie = true;
                    $scope.form_validation_msg_4ie = $scope.form_validation_msg_4ie + " " + $translate.instant('i18nUploadDoc.lbl_docType');
                    rt = false;
                }
            }

            if (rt) {
                // When validated, fetch real token, set the hidden input value for submit
                setHiddenInput('uploadForm','token', session.getTicket());
            }
            return rt;
        };


        window.uploadDoc_showResult = function () {
            var d = window.frames['uploadDoc_ResultFrame'].document;
            var resultStr = '';
            // IE Case
            if (!(window.isIE10UP === undefined) && !window.isIE10UP) {
                resultStr = $(d.body).text();
            }
            // Other browser case
            else if (d.getElementsByTagName('pre').length > 0 && d.getElementsByTagName('pre')[0].innerHTML != '') {
                resultStr = d.getElementsByTagName('pre')[0].innerHTML;
            }

            //Which means we have result
            if (resultStr != '') {
                var resultJson = angular.fromJson(resultStr);
                if (!(resultJson.KO === undefined)) {
                    //use $apply in asynchro call
                    $scope.$apply(function () {
                        $scope.failed = true;
                        $scope.errMsg = resultJson.KO;
                    }, 1000);
                } else {
                    //use $apply in asynchro call
                    $scope.$apply(function () {
                        $scope.finished = true;
                        $scope.resultMsg = 'i18nUploadDoc.msg_done';
                    }, 1000);

                }
            }
        };

        $scope.refreshGrid = function(){
            ezBus.broadcast('uploadDocFeature', 'gridFeature', 'RefreshGrid',$scope.finished);
            $scope.cancel();
        };

        //============== Init Feateure  ==============================
        $scope.resetValidate();
        $scope.initDropDownList();
        //============== End Init Feateure  ==============================
    }
]);
}());

Do you consider this code REALLY bad? If so, can you just show me the parts in my code that I have to change? I think it's nearly the best that I can do (I'm not an expert in Angular).

share|improve this question
    
Cross-posted from SO – Dan Pantry Mar 14 at 9:34
1  
As we all want to make our code more efficient or improve it in one way or another, try to write a title that summarizes what your code does, not what you want to get out of a review. – Jamal Mar 14 at 10:16
1  

Like it was pointed out in the SO post, your controller is doing too much, you really need to try and extract most logic on it to a directive or service.

I'm not sure you should list the dependencies of the controller one per line, is not going to help you debug the code

Since you are using var vm = this, which is a good approach, you could extend that to use the controllerAs feature on the router, so vm is binded to the controller in the html page, therefore most of the $scope use on the controller would be changed for vm (recommended reading)

The check if load failed can be done on the service itself. If what you need is checking if an http call returned an error code, use an http interceptor for that purpose (recommended reading)

reInitContext -> resetContext or restoreContext

The method uploadDoc_formValidate is performing a lot of 'jQuery' checks for data values. Bind those values to the ng-model and you can perform the validation directly on the form, with no need to call a function to do it for you. (recommended reading)

Also, the method uploadDoc_showResult is doing 'jQuery' checks, therefore I suggest you take a look on how the binding works between html and js in angular, then come up with a solution in an Angular way to show the result. Is easier than you may think.

Most of the 'doAutoSearch' logic can be extracted to a service, plus there are better methods to display an error than an alert

That was all, have fun!

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.