سؤال

Good Morning!

I've found several posts on stack that touch on this, but I haven't found any that accomplish what I'm trying to do exactly.

(JS Fiddle for Reference: http://jsfiddle.net/gsLXf/1/)

I have a dynamic set of questions that I am asking as part of a survey. I have figured out how to bind the responses in text and radio responses to a 'response' object that I can post back to my server. The problem I am having is with Checkboxes. As you can see in the fiddle, when I try to do

ng-model="response[question.id]"

all of my checkboxes respond as one item (which makes sense since they are all bound to the same value. However, when I use

ng-model="response[question.id][option.id]"

I pop an error because question.id hasn't been instantiated yet so option.id can't be pushed onto the object.

Ideally my response object for the referenced fiddle would look like this:

{
   "123456": "2", //radio question
   "789012": //checkbox question 
       ["5", "6"] //list of checkbox options ids selected
}

My users will be creating forms dynamically, so I have to be able to handle this very gracefully in all situations. I can't hard-code ANY object related data into a controller and I can't hand-create model objects to handle this situation.

I have considered looping through the known ID set to scaffold a response object to be filled during initialization, but it seems like overkill when Angular has such a nice way of just creating a response object on the fly (except for this situation).

What is the best way to go about doing this?

هل كانت مفيدة؟

المحلول

Here is a fiddle that does what you want: http://jsfiddle.net/2jVtH/

I have replaced the entire HTML with a directive, called cbb, used as:

<div cbb question="question" response="response"></div>

(this makes the original code cleaner too, IMHO, meaning I would do the same for the radio button)

The directive uses an isolated scope and in it puts an object that receives the check box values:

scope.model = {}

A deep $watch on this object updates an array with the values, so you get the desired response = { "789012": ["7", "8"] } format.

Directive full code:

surveyApp.directive("cbb", function() {
    return {
        restrict: "A",
        scope: {
            question: "=",
            response: "="
        },
        template:
            "<div class='text'>{{question.question}}</div>" +
            '<div class="options" ng-repeat="option in question.options">' +
                '<input type="checkbox" ng-model="model[option.id]" value="{{option.id}}"/> {{option.value}}' +
                '<tags ng-if="option.tags"></tags>' +
                '<action ng-if="option.action"></action>' +
            '</div>',
        link: function(scope, element, attrs) {
            if( !scope.response[scope.question.id] ) {
                scope.response[scope.question.id] = [];
            }
            var result = scope.response[scope.question.id];
            scope.model = {};
            scope.$watch("model", function(newval) {
                var x;
                result.splice(0);
                for( x in newval ) {
                    if( !newval.hasOwnProperty(x) ) continue;
                    if( newval[x] ) result.push(x);
                }
            }, true);
        }
    };
});

نصائح أخرى

I try my best on existed Angular directive and html, but it still have redundant empty string in array when checkbox unchecked.

And I use the ng-init

ng-init="response[question.id] = []"

jsfiddle:

http://jsfiddle.net/P9dsR/

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top