two way binding between input box and expression - angularjs

what would be the way to handle being able to change the expression from the text field and the other way around as well. For example:
myApp.controller('MainContrller', ['$scope', function($scope) {
$scope.inputs = {
'input1': 'text'
}
}]);
Then in the HTML:
<div ng-controller="MainController">
<input type="text" ng-model="inputs.input1">
<p>This will output {{ inputs.input1 }}</p>
</div>
This works well when the binding goes from the input to the expression, but I am also using contenteditable and would like for the expression in there to replace what is in the input box as well. Possible?

Look at the content editable example of ngModelController documentation, under section "Custom Control Example"
https://docs.angularjs.org/api/ng/type/ngModel.NgModelController
Basically it creates directive to bind the ng-model field to changes in content editable. You can then use the same ng-model expression to bind the contenteditable and input so changes are in sync.

Related

AngularJS - unchanged data passed by ng-model is interpreted as undefined instead of the value

I'm using Angular to generate some inputs and populate them with data using ng-repeat. I also want to bind the data inside the input to a save changes button which takes parameters provided by ng-model directives. save changes button prints the passed arguments using the built-in JS arguments object. For some reason, unless I change the text inside the input box, the output is [undefined, undefined]. Once I change the text inside the input boxes, the correct output is printed. Why is that?
JSfiddle code.
HTML:
<div ng-app="myApp" ng-controller="MainCtrl">
<p ng-repeat = "man in men">
<label>name</label><input type="text" ng-model="mname" ng-value="man.name"><br>
<label>status</label><input type="text" ng-model="mstatus" ng-value="man.status"><br>
<button ng-click="save(mname,mstatus)">
save changes
</button>
</p>
</div>
JS:
var app = angular.module('myApp', []);
app.controller('MainCtrl', function($scope) {
$scope.men = [{
name: "jon snow",
status: "depands"
}, {
name: "rob stark",
status: "dead"
}];
$scope.save = function() {
console.log(arguments);
}
});
This is not recommended but for your specific requirement you can use ng-init to bind ng-value to your model
<p ng-repeat = "man in men">
<label>name</label><input type="text" ng-model="mname" ng-value="man.name" ng-init="mname = man.name"><br>
<label>status</label><input type="text" ng-model="mstatus" ng-value="man.status" ng-init="mstatus = man.status"><br>
<button ng-click="save(mname,mstatus)">
save changes
</button>
</p>
This wouldn't bind your changes to the original model.
Fiddle
ngModel doesn't update untill you use a key to change it, or set it from your controller. Because you are setting the field of the input using ngValue, it doesn't register to your ngModel untill you change it.
This problem is similar to how most datepickers don't work with ngModel, as they set the field with DOM-manipulation and NOT by inserting the value by "key".
You can easily fix this by using the following HTML instead:
<label>name</label><input type="text" ng-model="man.name"><br>
<label>status</label><input type="text" ng-model="man.status"><br>
I simply removed the ngValue and linked the ngModel to your "man".

angular-selectize form's validation

I'm searching to set validation for an input caused by angular-selectize directive (https://github.com/machineboy2045/angular-selectize).
The problem is that this directive:
<selectize config="pic.interGermConfig" options="pic.interGermOptions" data-ng-model="pic.interGermFilter"></selectize>
Produces this output:
<selectize config="pic.interGermConfig" options="pic.interGermOptions" data-ng-model="pic.interGermFilter"></selectize>
<div class=“selectize-control”>
<div class=“selectize-input items not-full”>
<div data-value=“value” class=“item”>Visual value</div>
<input type=“text” autocomplete=“off” placeholder=“” />
</div>
<div class=“selectize-dropdown multi”>
<div class=“selectize-dropdown-content”>
<div data-value=“value” data-selectable class=“option”>Visual value</div>
</div>
</div>
This tag:
<input type=“text” autocomplete=“off” placeholder=“” />
doesn't have ng-model directive property, so I can't use a custom directive with ngModel require, to set input validity.
Is it possible to do this in some way or is it possible sets input validity inside a controller rather that inside a directive?
Thanks
I find a solution for my needs, but I think this isn't the best way to do this.
In a first moment, I've tried to use $watch on model passed to selectize directive, but this it's not allowed because ng-model attribute is obscured and not propagated to the new DOM element when use selectize.
So, looking angular-selectize code, I've seen that directive allows to use ng-required attribute (https://github.com/ptesser/angular-selectize/blob/master/dist/angular-selectize.js).
So I've created a function to checks model and sets errors in the controller and then I've passed this function to ng-require.
<selectize config="pic.interGermConfig" options="pic.interGermOptions"
data-ng-model="pic.interGermFilter"
data-ng-required="pic.checkSelectizeRequire(pic.interGermFilter, 'germs')">
</selectize>
And this is the function
function checkSelectizeRequire(array, filter){
array = array === undefined ? [] : array;
if (array.length === 0){
vm.errorFilter[filter] = true;
}else{
vm.errorFilter[filter] = false;
vm.dirtyFilter[filter] = true;
}
}
To check errors in the form, I've created my own variables, because I don't know how check 'required' option for selectize input like classic way:
form.inputName.$error.required

In angularjs, how to bind a label that contains html to a button

I have a button whose label changes based on the email address in the input. If it's "bob#example.com" the button says "Auto Login", other wise just say "Login"
<input ng-model="user.email" id="email" />
<button id="login" data-ng-focus data-ng-model="user.loginSubmit">{{user.email === "bob#example.com" ? "<em>Auto</em> Login" : "Login"}}</button>
When I remove the html around the 'Auto' the button works fine, otherwise angular doesn't render anything
Example JSFiddle
Any ideas?
Thanks,
It's because you can not use Html strings in side expressions directly. You have to use ng-bind-html or ng-bind-html-unsafe directives.
You can use ng-show/ng-hide
<span ng-show="user.email === 'bob#example.com'"><em>Auto</em></span>Login</button>
Here is your fiddle
Inline Angular expressions and ng-bind do not allow HTML inside. I suggest to replace inline text binding with ng-bind-html directive:
<button
id="login"
data-ng-focus
ng-model="user.loginSubmit"
ng-bind-html="user.email === 'bob#example.com' ? '<em>Auto</em> Login' : 'Login'"
></button>
ng-bind-html has dependency on ngSanitize, so you'll have to add it too:
var app = angular.module('myApp', [
'my.controllers',
'ngSanitize'
]);
Updated JSFiddle.

How to dynamically add input rows to view and maintain value in angularjs ng-model as array item

I have a situation where I want the user to dynamically add <input> rows when they want to enter a new item. As shown below, the user clicks the "Add Input Item" button and a new input element is added where the user may add text.
I'm trying to associate each input element value to the model $scope.items (an array) in app.js. In my index.html, I load the $scope.items using an ng-repeat.
What I do not understand is how I can get each input/row to automatically be added to & managed by the model defined as $scope.items.
Is it possible to map each input element to an ng-model that relates to the items array and, if so, how? Or, should directives be used in this situation?
The full code and runtime is on Plunker here (so that you can view the weird output).
Snippet from index.html:
<body ng-controller="MainCtrl">
<button ng-click="addInputItem()">+ Add Input Item</button>
<div ng-repeat="item in items">
<input ng-model="items" type="text" value="{{item}}" size="40">
</div>
<pre>items = {{items | json}}</pre>
</body>
The app.js code:
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.items = ['First Item', 'Second Item'];
$scope.addInputItem = function() {
$scope.items.push('');
};
});
The first problem is with the binding on the input boxes. Due to the ng-repeat surrounding the input box, each input box has an item value available to bind to, and that is what your ng-model should be. You shouldn't be assigning anything to the value attribute.
<input ng-model="item.value" type="text" size="40">
Making that change will at least get the input boxes to display the items. But typing in the boxes won't update the underlying array. That's the second problem.
The ng-repeat directive prototypically inherits the scope from your controller (read more about scope here). Since your items are primitive strings, the elements in your ng-repeat effectively get copies of the data from the controller, and typing in the boxes updates those copies, not the actual data in the controller.
To fix this, just make your items an array of objects instead of an array of strings.
$scope.items = [
{value:'First Item'},
{value: 'Second Item'}
];
Then you would bind your textboxes like this:
<input ng-model="item.value" type="text" size="40">
Here's a Plunker showing how it works.
This certainly is possible, check out this updated plnkr
I updated your array to be an array of objects (not strings) with a property of text and changed your inputs to this:
<input ng-model="item.text" type="text" size="40">

What's the difference between ng-model and ng-bind

I'm currently learning AngularJS and am having difficulty understanding the difference between ng-bind and ng-model.
Can anyone tell me how they differ and when one should be used over the other?
ng-bind has one-way data binding ($scope --> view). It has a shortcut {{ val }}
which displays the scope value $scope.val inserted into html where val is a variable name.
ng-model is intended to be put inside of form elements and has two-way data binding ($scope --> view and view --> $scope) e.g. <input ng-model="val"/>.
tosh's answer gets to the heart of the question nicely. Here's some additional information....
Filters & Formatters
ng-bind and ng-model both have the concept of transforming data before outputting it for the user. To that end, ng-bind uses filters, while ng-model uses formatters.
filter (ng-bind)
With ng-bind, you can use a filter to transform your data. For example,
<div ng-bind="mystring | uppercase"></div>,
or more simply:
<div>{{mystring | uppercase}}</div>
Note that uppercase is a built-in angular filter, although you can also build your own filter.
formatter (ng-model)
To create an ng-model formatter, you create a directive that does require: 'ngModel', which allows that directive to gain access to ngModel's controller. For example:
app.directive('myModelFormatter', function() {
return {
require: 'ngModel',
link: function(scope, element, attrs, controller) {
controller.$formatters.push(function(value) {
return value.toUpperCase();
});
}
}
}
Then in your partial:
<input ngModel="mystring" my-model-formatter />
This is essentially the ng-model equivalent of what the uppercase filter is doing in the ng-bind example above.
Parsers
Now, what if you plan to allow the user to change the value of mystring? ng-bind only has one way binding, from model-->view. However, ng-model can bind from view-->model which means that you may allow the user to change the model's data, and using a parser you can format the user's data in a streamlined manner. Here's what that looks like:
app.directive('myModelFormatter', function() {
return {
require: 'ngModel',
link: function(scope, element, attrs, controller) {
controller.$parsers.push(function(value) {
return value.toLowerCase();
});
}
}
}
Play with a live plunker of the ng-model formatter/parser examples
What Else?
ng-model also has built-in validation. Simply modify your $parsers or $formatters function to call ngModel's controller.$setValidity(validationErrorKey, isValid) function.
Angular 1.3 has a new $validators array which you can use for validation instead of $parsers or $formatters.
Angular 1.3 also has getter/setter support for ngModel
ngModel
The ngModel directive binds an input,select, textarea (or custom form control) to a property on the scope.
This directive executes at priority level 1.
Example Plunker
JAVASCRIPT
angular.module('inputExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.val = '1';
}]);
CSS
.my-input {
-webkit-transition:all linear 0.5s;
transition:all linear 0.5s;
background: transparent;
}
.my-input.ng-invalid {
color:white;
background: red;
}
HTML
<p id="inputDescription">
Update input to see transitions when valid/invalid.
Integer is a valid value.
</p>
<form name="testForm" ng-controller="ExampleController">
<input ng-model="val" ng-pattern="/^\d+$/" name="anim" class="my-input"
aria-describedby="inputDescription" />
</form>
ngModel is responsible for:
Binding the view into the model, which other directives such as
input, textarea or select require.
Providing validation behavior (i.e. required, number, email, url).
Keeping the state of the control (valid/invalid, dirty/pristine,
touched/untouched, validation errors).
Setting related css classes on the element (ng-valid, ng-invalid,
ng-dirty, ng-pristine, ng-touched, ng-untouched) including
animations.
Registering the control with its parent form.
ngBind
The ngBind attribute tells Angular to replace the text content of the specified HTML element with the value of a given expression, and to update the text content when the value of that expression changes.
This directive executes at priority level 0.
Example Plunker
JAVASCRIPT
angular.module('bindExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.name = 'Whirled';
}]);
HTML
<div ng-controller="ExampleController">
<label>Enter name: <input type="text" ng-model="name"></label><br>
Hello <span ng-bind="name"></span>!
</div>
ngBind is responsible for:
Replacing the text content of the specified HTML element with the
value of a given expression.
If you are hesitating between using ng-bind or ng-model, try to answer these questions:
Do you only need to display data?
Yes: ng-bind (one-way binding)
No: ng-model (two-way binding)
Do you need to bind text content (and not value)?
Yes: ng-bind
No: ng-model (you should not use ng-bind where value is required)
Is your tag a HTML <input>?
Yes: ng-model (you cannot use ng-bind with <input> tag)
No: ng-bind
ng-model
ng-model directive in AngularJS is one of the greatest strength to bind the variables used in application with input components. This works as two way data binding. If you want to understand better about the two way bindings, you have an input component and the value updated into that field must be reflected in other part of the application. The better solution is to bind a variable to that field and output that variable whereever you wish to display the updated value throughoput the application.
ng-bind
ng-bind works much different than ng-model. ng-bind is one way data binding used for displaying the value inside html component as inner HTML. This directive can not be used for binding with the variable but only with the HTML elements content. Infact this can be used along with ng-model to bind the component to HTML elements. This directive is very useful for updating the blocks like div, span, etc. with inner HTML content.
This example would help you to understand.
angular.module('testApp',[]).controller('testCTRL',function($scope)
{
$scope.testingModel = "This is ModelData.If you change textbox data it will reflected here..because model is two way binding reflected in both.";
$scope.testingBind = "This is BindData.You can't change this beacause it is binded with html..In above textBox i tried to use bind, but it is not working because it is one way binding.";
});
div input{
width:600px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<head>Diff b/w model and bind</head>
<body data-ng-app="testApp">
<div data-ng-controller="testCTRL">
Model-Data : <input type="text" data-ng-model="testingModel">
<p>{{testingModel}}</p>
<input type="text" data-ng-bind="testingBind">
<p ng-bind="testingBind"></p>
</div>
</body>
ngModel usually use for input tags for bind a variable that we can change variable from controller and html page but ngBind use for display a variable in html page and we can change variable just from controller and html just show variable.
We can use ng-bind with <p> to display, we can use shortcut for ng-bind {{model}}, we cannot use ng-bind with html input controls, but we can use shortcut for ng-bind {{model}} with html input controls.
<input type="text" ng-model="name" placeholder="Enter Something"/>
<input type="text" value="{{name}}" placeholder="Enter Something"/>
Hello {{name}}
<p ng-bind="name"</p>

Resources