3

I'm generating a report with collection of questions.

app.controller('reportCtrl', ['$scope','$stateParams', function ($scope, $stateParams) {

    $scope.questions: [
        { questionkey: 1, questiontext: 'Type', questiontype: 1 , questionmodel:'accsType' },
        { questionkey: 2, questiontext: 'Reported By', questiontype: 1, questionmodel: 'accsReportedBy' },
        { questionkey: 3, questiontext: 'Time and Date', questiontype: 6, questionmodel: 'accsCurrentDate' },
        { questionkey: 4, questiontext: 'Address', questiontype: 2, questionmodel: 'accsAddress' },
        { questionkey: 5, questiontext: 'Coordinates', questiontype: 6, questionmodel: 'accsCoordinates' },
        { questionkey: 6, questiontext: 'Blank', questiontype: 1, questionmodel: 'accsBlank1' },
        { questionkey: 7, questiontext: 'Blank', questiontype: 1, questionmodel: 'accsBlank2' },
        { questionkey: 8, questiontext: 'Blank', questiontype: 1, questionmodel: 'accsBlank3' },
        { questionkey: 9, questiontext: 'Blank', questiontype: 1, questionmodel: 'accsBlank4' },
        { questionkey: 10, questiontext: 'Details of Survey', questiontype: 2, questionmodel: 'accsDetailsSurvey' },
        { questionkey: 11, questiontext: 'Photos', questiontype: 5, questionmodel: 'accsPhotos' }
    ];

}]);

and I've created a custom directive to draw the questions according to the question types Eg question type 1 is text box type 2 is textarea

<question contents="questions"></question>

app.directive('question', function ($compile) {
    return {
        transclude: true,
        restrict: 'E',
        scope: {
            contents: '='
        },  
        link: function (scope, element, attrs) {   
            angular.forEach(scope.contents, function (k, v) {
                var ele;

                switch (parseInt(k.question.questiontype)) {
                    case 1:
                        ele = $compile("<accstextbox data='k.question'></accstextbox>")(scope);
                        break;
                    case 2:
                        ele = $compile("<accstextarea data='k.question'></accstextarea>")(scope);
                        break;
                }

                element.append(ele);
            });
        }         
    };
});

I've created a directive for each question types

app.directive('accstextbox', [function () {
    return {
        restrict: 'E',
        templateUrl: 'app/directives/questions/textbox.html',
        link: function (scope, element, attrs) {
           console.log(scope.data); // undefined
        },
        scope:{
            data: '='
        }
    };
}]);

app.directive('accstextarea', [function () {
    return {
        restrict: 'E',
        templateUrl: 'app/directives/questions/textarea.html',
         link: function (scope, element, attrs) {
           console.log(scope.data); // undefined
        },
        scope: {
            data: '='
        }
    };
}]);

when i dynamically add those directives, i'm passing the data object via attribute. that data object is undefined in the child directive scope. first time i'm using angularjs for my project.

2 Answers 2

1

Your solution will not work since k is a local variable and is no accessible for the $compiler service.

A solution for this is to make your directive use ngRepeat and ngIf to generate the final layout through templates:

app.directive('question', function ($compile) {
    return {
        transclude: true,
        restrict: 'E',
        templateUrl: 'app/directives/questions.html',
        scope: {
            contents: '='
        }      
    };
});

And the app/directives/questions.html:

<div ng-repeat="question in contents">
    <accstextbox ng-if="question.questiontype == 1" data="question"></accstextbox>
    <accstextarea ng-if="question.questiontype == 2" data="question"></accstextarea>
</div>

Since this is a really small template, you may add it to the template configuration parameter of the directive, instead of loading it from the server through templateUrl.

Hope this will help you!

Sign up to request clarification or add additional context in comments.

3 Comments

i just showed only two questions type for simplicity, but please see this question stackoverflow.com/questions/26093809/…. this is a angular js version issue?
No, it is not. Note that the scope of addDirective is the same as the MainCtrl scope, which defines $scope.data. Also, this is the scope being given to the $compiler directive, thus making things work. This setup is a lot sensible to changes and things are not exactly encapsulated, therefore I do not recommend it.
yes you are correct. i misunderstood the question answer. i'll change that with ng-if
1

As Vinicius noted, you're using the k object inside the forEach loop in a text string so angular can't resolve what you mean by k.questions.

I propose a similar solution to repeat the questions in an ng-repeat inside your question directive:

<div>
  <div ng-repeat="q in contents">
    <div ng-switch="q.questiontype">
      <div ng-switch-when="1">
        <accstextbox> one: {{q.questiontext}}</accstextbox>
      </div>
      <div ng-switch-when="2">
        <accstextarea> two : {{q.questiontext}}</accstextarea>
      </div>
    </div>
  </div>
</div>

Another option is to move the logic of selecting the type of template into the child directive. I would prefer this option if your only change is the type of input, and there is not much difference in the logic, so you would avoid duplicating your code, i.e the child directive template would contain the input selection logic:

<div>
  <div ng-if="question.questiontype === 1">
    <input type="text"/>
  </div>
  <div ng-if="question.questiontype === 2">
    <textarea name="" id="" cols="30" rows="10"></textarea>
  </div>
</div>

2 Comments

but i'm passing more objects to customize each control. that object contains css class, lable name, model value etc. that what i have created a seperate template html for each control and accessed via templateUrl. please see this questions stackoverflow.com/questions/26093809/…
Those properties css class, label name, model value are all supported in both above cases. If you're suggesting that you have multiple different fields in the child directives, then it's better to use the option with an ngSwitch or ngIf in the parent directive and separate the child directives.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.