Search Posts

Create controllers in ng-repeat directive

I am trying to refactor my AngularJS code. My goal is to create dynamically controllers responsible for view of data from REST API. My idea is to use ng-repeat directive and inside it create div with ng-controller directive with parameter from ng-repeat output. Unfortunatelly I don’t know how to pass data to single iteration.

AngularJS code

(function () {
    'use strict';

    angular
        .module('App')
        .controller('ActionData', ActionData);

    ActionData.$inject = ['$scope', 'AlertService', '$http', 'taskId', '$state', '$timeout', '$uibModal', 'toastr'];

    function ActionData($scope, AlertService, $http, taskId, $state, $timeout, $uibModal, toastr) {

        var vm = this;

        vm.taskId = taskId;

        vm.errorNoQuestions = false;

        vm.indexPosition = 0;

        vm.taskVariables = null; // vital configuration of task

        vm.compilation = {
            ok: true,
            msg: ""
        };

        $scope.allQuestions = [];
        $scope.allAnswers = [];

        $scope.activeTabIndex = 1;

        vm.seenAt = null;

        vm.showQuestionsTab = function () {
            if (vm.taskVariables === null) {
                $http
                    .get('api/toDoAction/taskVariables/' + taskId)
                    .then(
                        function (response) {
                            vm.taskVariables = response.data;
                            $scope.metadata = vm.taskVariables.metadata; // setting metadata
                            renderQuestions();
                            if (vm.taskVariables === null) {
                                $state.go('toDoAction-unauthorized');
                            }
                        },
                        function () {
                            $state.go('toDoAction-unauthorized');
                        }
                    );
            } else {
                renderQuestions();
            }
        };

        function renderQuestions() {
            vm.errorNoQuestions = false;
            if ($scope.allQuestions.length === 0) {
                $http
                    .get('api/toDoAction/getQuestions/' + taskId)
                    .then(
                        function (response) {
                            if (response.data.length === 0) {
                                vm.errorNoQuestions = true; // showing error when no questions are available
                                $scope.allQuestions = [];
                                toastr.warning('No questions available at this moment', 'Warning!', {
                                    progressBar: true,
                                    timeOut: 1500
                                });
                            } else {
                                initializeNewQuestions(response.data); // initialization of new questions
                            }
                        },
                        function () {
                            AlertService.warning("Unable to retrieve questions for toDoAction!");
                            vm.errorNoQuestions = true; // showing error when no questions are available
                        }
                    );
            }
        }


        vm.closetoDoActionTab = function($event, $selectedIndex) {
            if ($selectedIndex === 1) {
                return;
            }
            if ($event === undefined) { // it was force changed so we wanna switch it
                console.log("code changed");
            } else { // action triggered by user so prompt is mandatory here
                $event.preventDefault();
                $uibModal.open({
                    templateUrl: 'app/confirm/confirm-dialog.html',
                    controller: 'ConfirmDialogController',
                    controllerAs: 'vm',
                    size: 'md',
                    backdrop: 'static',
                    resolve: {
                        text: function() {
                            return '

Are you sure you want to switch to answer correction?

' + '

Your currently assigned questions may be dispatched to someone else!

'; } } }).result.then(function() { console.log("wanna switch"); var ids = []; angular.forEach($scope.allQuestions, function(value, index) { ids.push(value.id); }); $scope.allQuestions = []; $scope.allAnswers = []; $scope.answers = []; $scope.questions = []; $http.post('api/toDoAction/return/' + vm.taskId, ids); if ($selectedIndex === 2) { return $state.go('toDoAction.answers'); } else if ($selectedIndex === 0) { return $state.go('toDoAction.description'); } }, function() { console.log("aborted"); }); } }; vm.submitQuestion = function (qIndex) { var body = { id: $scope.questions[qIndex].id, content: $scope.questions[qIndex].content, answer: $scope.answers[qIndex], seenAtTimestamp: vm.seenAt, //fixme answerAtTimestamp: (new Date).getTime() }; vm.seenAt = (new Date).getTime(); $http .post('api/toDoAction/answer', body) .then(function () { $scope.questions[qIndex].sent = true; $scope.questions[qIndex].submitted = true; toastr.success('Answer has been saved!', 'Success!', { progressBar: true, timeOut: 1500 }); tryRenderNextQuestionPage(); }, function () { tryRenderNextQuestionPage(); }); }; vm.skipQuestion = function (qIndex) { $http .post('api/toDoAction/skip/' + $scope.questions[qIndex].id) .then(function () { $scope.questions[qIndex].sent = true; $scope.questions[qIndex].skipped = true; toastr.warning('Question skipped', 'Success!', { progressBar: true, timeOut: 1500 }); tryRenderNextQuestionPage(); }, function() { toastr.error('Question not skipped, an error occurred', 'Warning!', { progressBar: true, timeOut: 1500 }); tryRenderNextQuestionPage(); }); }; function initializeNewQuestions(newQuestions) { // this is not empty list! $scope.allAnswers = []; $scope.allQuestions = newQuestions; $scope.allQuestions.forEach(function () {$scope.allAnswers.push({answered: false});}); $scope.metadata = vm.taskVariables.metadata; initializeQuestionPackage(0); } function initializeQuestionPackage(indexPositionUpdated) { console.log('init qpackage func'); vm.indexPosition = indexPositionUpdated; var newQuestions = []; var newAnswers = []; for (var i = vm.indexPosition; i = $scope.allQuestions.length) { // index out of bound console.log('break ' + i); break; } newAnswers.push($scope.allAnswers[i]); newQuestions.push($scope.allQuestions[i]); } $scope.answers = null; $scope.questions = null; setTimeout(function () { $scope.answers = newAnswers; $scope.questions = newQuestions; }, 0); } function allQuestionsSent() { for (var i in $scope.questions) { if ($scope.questions[i].sent !== true) { return false; } } return true; } function tryRenderNextQuestionPage() { if (allQuestionsSent() !== true) { console.log('not all questions sent'); return; } if (vm.indexPosition + vm.taskVariables.renderedQuestions > $scope.allQuestions.length - 1) { console.log("used all questions, polling new ones"); $scope.allQuestions = []; $scope.questions = []; $scope.answers = []; renderQuestions(); return; } initializeQuestionPackage(vm.indexPosition + vm.taskVariables.renderedQuestions); } $scope.$on('questionDivsCreated', function(questionDivsCreated) { console.log("repeat finished"); renderTask(); }); vm.compilation.ok = true; function renderTask() { vm.compilation.ok = true; // setting initial successful status of compilation for (var i in $scope.questions){ $('#' + vm.getIndexOfQuestionDiv(i)).html(vm.taskVariables.template); } for (var i in $scope.questions) { // iteration over all questions $scope.questionIndex = i; if (vm.compilation.ok === false) break; // no need to compile next scripts for (var key in vm.taskVariables.widgets) { // applying widgets per question if (vm.compilation.ok === false) break; // no need to compile next scripts var widgetName = vm.taskVariables.widgets[key].name; try { var obj = {}; obj.metadata = $scope.metadata; obj.question = $scope.questions[i].content; var theTemplate = Handlebars.compile(vm.taskVariables.widgets[key].template); $('#' + vm.getIndexOfQuestionDiv(i)) .find('[data-widget-name="' + widgetName + '"]') .html(theTemplate(obj)); } catch(e) { var err = e.constructor('Error in widget "' + key + '". ' + e.message); vm.compilation = { // in case of any errors in template ok: false, msg: err.toString() } } try { eval(vm.taskVariables.widgets[key].config); } catch (e) { console.log(e); var err = e.constructor('Error in widget "' + key + '". ' + e.message); err.lineNumber = e.lineNumber - err.lineNumber + 3; vm.compilation = { // in case of any errors in script ok: false, msg: err.toString() } } } } vm.seenAt = (new Date).getTime(); document.body.scrollTop = document.documentElement.scrollTop = 0; if ($scope.questions.length !== 1) { toastr.success('New question package has been initialized.', { progressBar: true, timeOut: 1500 }); } } // ------------------------------------- // functions for widgets JS configuration // ------------------------------------- $scope.getQuestionDOM = function (qIndex) { if ($scope.activeTabIndex === 1) { // getting dom when TASK tab is present return $('#' + vm.getIndexOfQuestionDiv(qIndex)); } return $('#' + vm.getIndexOfAnswerDiv(qIndex)); }; $scope.getQuestion = function(questionIndex) { if ($scope.activeTabIndex === 1) { // getting dom when TASK tab is present return $scope.questions[questionIndex].content } return $scope.answeredQuestions[questionIndex].content }; $scope.getMetadata = function() { return $scope.metadata; }; $scope.getAnswer = function(questionIndex) { if ($scope.activeTabIndex === 1) { // getting dom when TASK tab is present return $scope.answers[questionIndex]; } return $scope.answeredAnswers[questionIndex]; }; $scope.getMetadata = function() { return $scope.metadata; }; vm.getIndexOfQuestionDiv = function idOfQuestionDiv(qIndex) { return 'question_' + qIndex; }; vm.getIndexOfAnswerDiv = function idOfAnswerDiv(qIndex) { return 'answer_' + qIndex; }; } })();

HTML code

<uib-tab index="1" select="vm.showQuestionsTab()" deselect="vm.closetoDoActionTab($event, $selectedIndex)">
    <uib-tab-heading>
        <span> data</span>
    </uib-tab-heading>

    <div class="row main-padding">
        <div class="col-md-12">
            <div class="alert alert-danger alert-dismissible materialize-red darken-1" ng-show="vm.compilation.ok == false" style="margin-top: 20px;">
                <a class="close" data-dismiss="alert" aria-label="close">×</a>
                <h4><strong>Error!</strong></h4>
                <hr>
                <p>{{vm.compilation.msg}}</p>
            </div>

            <div ng-show="vm.errorNoQuestions == true">
                <h3><strong>All questions locked!</strong></h3>
                <hr>
                <div class="grey-text text-lighten-1">
                    <p>You can not provide more answers at this moment. All available questions are
                        currently dispatched to other linguists.</p>
                    <p>Questions are being dispatched for 20 minutes. If answer was not provided, question is available for toDoAction by other user</p>
                    <p>During this idle time, would you like to check out other active tasks?</p>
                </div>
                <button type="button" class="btn btn-success btn-sm btn-raised" ui-sref="active-tasks" style="text-transform: none">
                    <span>Available tasks</span>
                </button>
            </div>
            <div id="task-placeholder">
                <div ng-repeat="q in questions track by $index">
                    <div ng-controller="ShowQuestion"
                         ng-class="{'panel-warning': questions[$index].skipped == true, 'panel-success': questions[$index].submitted == true}"
                         on-finish-render="questionDivsCreated">

                    <hr style="visibility: hidden" class="margin-top-zero">
                    <div>
                        <button type="button" class="btn btn-success no-margin-vertical"
                                ng-disabled="answers[$index].answered == false || questions[$index].sent == true"
                                ng-class="{'btn-raised': answers[$index].answered == true}"
                                ng-click="vm.submitQuestion($index)">
                            Submit answer
                        </button>
                        <button type="button" class="btn btn-warning no-margin-vertical pull-right btn-raised"
                                ng-disabled=" questions[$index].sent == true"
                                ng-click="vm.skipQuestion($index)">
                            Skip to next question
                        </button>
                    </div>
                    <hr>
                    <div id="{{vm.getIndexOfQuestionDiv($index)}}">
                        </div>
                </div>
                </div>
                <!-- task renders here -->
            </div>
            <hr>
            <div class="row">
                <div class="col-md-12">
                    <button class="btn btn-warning pull-left btn-raised"
                            ng-click="vm.skipCurrentQuestion()"
                            ng-show="answer != null"
                            ng-disabled="answer == null">
                        <span>
                            Skip question
                        </span>
                    </button>

                </div>
            </div>
        </div>
    </div>
</uib-tab>

Source: AngularJS

Leave a Reply

Your email address will not be published. Required fields are marked *