1

Here is a simple Angular example:

<!DOCTYPE html>
<html ng-app="GenericFormApp">
<head>
    <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.min.js"></script>    
</head>
<body ng-controller="GenericFormCtrl as ctrl">    
    <div>
        Model: {{ctrl.model}}
    </div>
    <div>
        <input ng-model="ctrl.model" />
    </div>
    <div>
        <input type="button" value="Alert model" ng-click="ctrl.showModel();" />
    </div>
    <script>        
        angular.module("GenericFormApp", [])
            .controller("GenericFormCtrl", [function () {               
                this.showModel = function () { alert(this.model); };
            }])        
    </script>
</body>
</html>

The above shows how to bind an input to a model, a fundamental feature of Angular.

It also allows the user to pop up a modal dialog with the contents of the input. This works fine except when the input is left blank.

In that case, it displays "undefined".

I could, of course, simply write a line of code that sets the initial value of the model to a blank string, but this is not particularly practical because in my real application, there are many inputs, and the user may leave any number of them blank.

In short, I want to know how to make it so that Angular knows that a blank input should contain a blank string in the model.

Vivian River
  • 31,198
  • 62
  • 198
  • 313
  • 1
    due to how JavaScript works, the variable `this.model` doesn't actually **exist** until a value is put into it. your alert which is displaying `undefined` is doing so because the variable hasn't been created yet. you could write a conditional like `alert(this.model || "");`, but you can't change how JavaScript prints variables that don't exist. Also, you don't want every property in your model to be `""`, as this would cause unnecessary data transfers. – Claies Sep 14 '15 at 21:37
  • You are correct to say that `this.model` doesn't exist until a value is put into it. Angular is putting a value into it for me when the user keys something in. I would like to know how to make it so that Angular will put a blank string into this model when the user doesn't enter anything; just like a jQuery app would read a blank string from a blank input. – Vivian River Sep 14 '15 at 21:39
  • aside from using [getter setter on `ng-model`](https://docs.angularjs.org/api/ng/directive/ngModel#!), you would have to do it property by property. – Claies Sep 14 '15 at 21:41

2 Answers2

2

I would go with custom directive to extend default input directive behaviour. So in case if input has a model this directive would check if this model is undefined and if so assign it an empty string value.

<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.min.js"></script>
<div ng-app="GenericFormApp" ng-controller="GenericFormCtrl as ctrl">    
    
    <input ng-model="ctrl.model" /> {{ctrl.model}}<br>
    <input type="button" value="Alert model" ng-click="ctrl.showModel();" />
    
    <script>        
        angular.module("GenericFormApp", [])
            .controller("GenericFormCtrl", [function () { 
                this.showModel = function () { alert(this.model); };
            }])   
            .directive("input", function($parse) {
                return {
                    link: function(scope, element, attr, ngModelController) {
                        if (attr.ngModel) {
                            var model = $parse(attr.ngModel);
                            if (typeof model(scope) === 'undefined') {
                                model.assign(scope, '');    
                            }
                        }
                    }
                };
            });
    </script>
</div>
dfsq
  • 191,768
  • 25
  • 236
  • 258
0

I igree with @Claies, but, if you need this for some specific attributes, you can use ng-init:

<input type="text" ng-init="ctrl.model = ctrl.model || ''" ng-model="ctrl.model"/>

or create a specific directive, like 'auto-init' or similar, not directly on input element.

Joao Polo
  • 2,153
  • 1
  • 17
  • 26