Passing dynamic value with single quote as a ng-true-value expression fails

Problem

I have my checkbox input that sets the "true" value dynamically based on a variable trueVal, which is a string.

<input ng-model="foo" ng-true-value="'{{trueVal}}'">

For example, for trueVal = "something", foo === "something" when the checkbox is checked.

This works except in the case when trueVal equals to a string with a single quote in it: Customer didn't understand. In this case, there is an error:

Error: [$parse:lexerr] Lexer Error: Unterminated quote at columns 27-28 ['] in expression ['Customer didn't understand'].

I can't strip the single quotes because the string should be set as-is to foo.

Broader context:

I'm creating a group of checkboxes based on a list of options that I get from the back-end:

<div ng-repeat="(key,option) in options">
  <input type="checkbox" 
         ng-model="foo[key]"
         ng-true-value="'{{option.trueVal}}'"
         ng-false-value="null">
</div>

So, given:

options =  {
             0: {trueVal: "Customer was late"},
             1: {trueVal: "Customer didn't understand"}
           };

I expect to see:

foo = {
  1: "Customer didn't understand"
};

if the second box is checked.

Problem courtesy of: Paul Stanley

Solution

The short version, ng-true-val expects a constant and is being passed the following expression as a parameter: 'Customer didn't understand' for evaluation, which is malformed because of un-terminated single quote.

The simple (but somewhat ugly) approach would be to replace ' with \' in the View (this doesn't change the actual value - just encodes it):

<input type="checkbox" ng-model="foo"
       ng-true-value="'{{trueVal.replace('\'', '\\\'')}}'"
       ng-false-value="null">

The better approach is probably using ng-change:

<input type="checkbox" ng-model="t"
       ng-change="foo = t ? trueVal : null">

Longer version

Under the covers ng-true-value calls $parse service: var parseFn = $parse(expression), and expects parseFn.constant === true. The latter is only true if the expression is a constant:

expression = 'string';      // string literal
expression = '5'            // number literal
expression = {v: 'string'}  // object literal with a constant
expression = 'foo' + 'bar'; // expression that evaluates to a constant

In your case you need to take the variable trueVal, interpolate it to a value {{trueVal}}, to become part of an expression '{{trueVal}}' that ultimately will be evaluated as explained above.

This is why substitution of ' works to \', because it escapes the singles quotes as if you have written the expression directly:

ng-true-value="'Customer didn\'t understand'"

If you are certain that you won't have double quotes (") in your values for options, you could also simply reverse the order of quotes without the need to do replace:

ng-true-value='"{{trueVal}}"`

This will, of course, fail for the same reason if trueVal value had double quotes: something with "quotes".

Solution courtesy of: New Dev

Discussion

Try this.

In Markup

<input type="checkbox" ng-model="dummyModel" ng-model-options="{getterSetter: true}">

In Controller

var trueValue = "my true' value";
var falseValue = false;
var _model;
$scope.dummyModel = function (val) {
    if (angular.isDefined(val)) {
        _model = val ? trueValue : falseValue
    }
    return _model === trueValue;
}

Use _model to submit to the database.

Discussion courtesy of: Vinay K

This recipe can be found in it's original form on Stack Over Flow.