Change value of input placeholder via model? - angularjs

I'm trying to change the value of the input placeholder from a controller but cant quite figure out how.
input(type='text', ng-model='inputText', side='30', placeholder='enter username')
Is there a way to modify a model's element attributes?

You can bind with a variable in the controller:
<input type="text" ng-model="inputText" placeholder="{{somePlaceholder}}" />
In the controller:
$scope.somePlaceholder = 'abc';

The accepted answer still threw a Javascript error in IE for me (for Angular 1.2 at least). It is a bug but the workaround is to use ngAttr detailed on https://docs.angularjs.org/guide/interpolation
<input type="text" ng-model="inputText" ng-attr-placeholder="{{somePlaceholder}}" />
Issue: https://github.com/angular/angular.js/issues/5025

Since AngularJS does not have directive DOM manipulations as jQuery does, a proper way to modify attributes of one element will be using directive.
Through link function of a directive, you have access to both element and its attributes.
Wrapping you whole input inside one directive, you can still introduce ng-model's methods through controller property.
This method will help to decouple the logic of ngmodel with placeholder from controller.
If there is no logic between them, you can definitely go as Wagner Francisco said.

As Wagner Francisco said, (in JADE)
input(type="text", ng-model="someModel", placeholder="{{someScopeVariable}}")`
And in your controller :
$scope.someScopeVariable = 'somevalue'

Related

How to use ng-model as element rather than attribute?

I want to use ng-model directive as element rather than as attribute inside tag,is there any way to do it?
well I've already designed my webpage in html and javascript and I want to include it in angularJS using "ng-include". So rather than adding attribute like,
<input type="checkbox" id="checkbox" name='rejectedPartsConfirmtodothis' ng-model="reject">
I want to put it in the format like, (as said in angulaJS documentation )
<ng-model>
<input --->
</ng-model>
but this is not working, any idea how can I make it work?
Quoting the content of the page
Usage
as element: (This directive can be used as custom element, but be aware of IE restrictions).
<ng-model>
...
</ng-model>
according to v1.5 official documentation : https://docs.angularjs.org/api/ng/directive/ngModel
Usage
as element: (This directive can be used as custom element, but be aware of IE restrictions).
<ng-model>
...
</ng-model>
I dont really think there would be a use case where you would really need to do this...instead try some alternative but use ng-model as an attribute as ng-model is a pre-defined directive given by angularjs...
You can build a new directive but you cannot modify ng-model to work as an element.

angularjs binding from view to controller

I want to do a two way data-binding from my view to controller. is it possible to do it using ng-model? it displays undefined in the controller though.
My code is something like:
<span ng-model="xyz">${user.group}</span>
and in my controller:
console.log($scope.xyz); //returns undefined.
What is the use of ng-model if I cannot use it this way?
Can anyone suggest a workaround for this?
Your problem is that the ng-model must be bound to an actual value. Spans do not have a value associated to them like inputs do so your $scope.xyz would never be set unless you set it in the scope. Even after that it would not do anything with the span. You also need double {{ and }} around everything, not single {}. You also do not need the $ symbol in the html.
Try :
<input type="text" ng-model="xyz" /> <span> {{xyz}} </span>
Got it working, I was missing to pass the argument to this function as a string, I simply had to do this using ng-bind on span tag like this:
ng-bind="getGp('${user.group}')"
Thanks everyone.

Cannot get textarea value in angularjs

Here is my plnkr: http://plnkr.co/edit/n8cRXwIpHJw3jUpL8PX5?p=preview You have to click on a li element and the form will appear. Enter a random string and hit 'add notice'. Instead of the textarea text you will get undefined.
Markup:
<ul>
<li ng-repeat="ticket in tickets" ng-click="select(ticket)">
{{ ticket.text }}
</li>
</ul>
<div ui-if="selectedTicket != null">
<form ng-submit="createNotice(selectedTicket)">
<textarea ng-model="noticeText"></textarea>
<button type="submit">add notice</button>
</form>
</div>
JS part:
$scope.createNotice = function(ticket){
alert($scope.noticeText);
}
returns 'undefined'. I noticed that this does not work when using ui-if of angular-ui. Any ideas why this does not work? How to fix it?
Your problem lies in the ui-if part. Angular-ui creates a new scope for anything within that directive so in order to access the parent scope, you must do something like this:
<textarea ng-model="$parent.noticeText"></textarea>
Instead of
<textarea ng-model="noticeText"></textarea>
This issue happened to me while not using the ng-if directive on elements surrounding the textarea element. While the solution of Mathew is correct, the reason seems to be another. Searching for that issue points to this post, so I decided to share this.
If you look at the AngularJS documentation here https://docs.angularjs.org/api/ng/directive/textarea , you can see that Angular adds its own directive called <textarea> that "overrides" the default HTML textarea element. This is the new scope that causes the whole mess.
If you have a variable like
$scope.myText = 'Dummy text';
in your controller and bind that to the textarea element like this
<textarea ng-model="myText"></textarea>
AngularJS will look for that variable in the scope of the directive. It is not there and thus he walks down to $parent. The variable is present there and the text is inserted into the textarea. When changing the text in the textarea, Angular does NOT change the parent's variable. Instead it creates a new variable in the directive's scope and thus the original variable is not updated. If you bind the textarea to the parent's variable, as suggested by Mathew, Angular will always bind to the correct variable and the issue is gone.
<textarea ng-model="$parent.myText"></textarea>
Hope this will clear things up for other people coming to this question and and think "WTF, I am not using ng-if or any other directive in my case!" like I did when I first landed here ;)
Update: Use controller-as syntax
Wanted to add this long before but didn't find time to do it. This is the modern style of building controllers and should be used instead of the $parent stuff above. Read on to find out how and why.
Since AngularJS 1.2 there is the ability to reference the controller object directly instead of using the $scope object. This may be achieved by using this syntax in HTML markup:
<div ng-controller="MyController as myc"> [...] </div>
Popular routing modules (i.e. UI Router) provide similar properties for their states. For UI Router you use the following in your state definition:
[...]
controller: "MyController",
controllerAs: "myc",
[...]
This helps us to circumvent the problem with nested or incorrectly addressed scopes. The above example would be constructed this way. First the JavaScript part. Straight forward, you simple do not use the $scope reference to set your text, just use this to attach the property directly to the controller object.
angular.module('myApp').controller('MyController', function () {
this.myText = 'Dummy text';
});
The markup for the textarea with controller-as syntax would look like this:
<textarea ng-model="myc.myText"></textarea>
This is the most efficient way to do things like this today, because it solves the problem with nested scopes making us count how many layers deep we are at a certain point. Using multiple nested directives inside elements with an ng-controller directive could have lead to something like this when using the old way of referencing scopes. And no one really wants to do that all day!
<textarea ng-model="$parent.$parent.$parent.$parent.myText"></textarea>
Bind the textarea to a scope variable's property rather than directly to a scope variable:
controller:
$scope.notice = {text: ""}
template:
<textarea ng-model="notice.text"></textarea>
It is, indeed, ui-if that creates the problem. Angular if directives destroy and recreate portions of the dom tree based on the expression. This is was creates the new scope and not the textarea directive as marandus suggested.
Here's a post on the differences between ngIf and ngShow that describes this well—what is the difference between ng-if and ng-show/ng-hide.

How do I access the child ngModel from a directive?

Like in this question, I want to add .error on a form field's parent .control-group when scope.$invalid is true.
However, hardcoding the form name like in ng-class="{ error: formName.fieldModel.$invalid }" means that I can't reuse this in different forms, plus I'd rather not repeat this declaration everywhere.
I figured that a directive that looks something like this could work:
<div class="control-group" error-on="model1, model2">
<input ng-model="model1">
<input ng-model="model2">
</div>
So when either model1 or model2 is not valid, .control-group gets .error added.
My attempt here. Is it possible to access the models from the directive, given the model names?
If there's a better approach, I'd love to hear it too.
I don't think that writing a custom directive is necessery for this use-case as the ng-form directive was created exactly for situations like those. From the directive's documentation:
It is useful to nest forms, for example if the validity of a sub-group
of controls needs to be determined.
Taking your code as an example one would write:
<div class="control-group" ng-class="{ error: myControlGroup1.$invalid }>
<ng-form name="myControlGroup1">
<input ng-model="model1">
<input ng-model="model2">
</ng-form>
</div>
By using this technique you don't need to repeat expressions used in ng-model and can reuse this fragment inside any form.
You can also change the markup in the accepted answer to do without the nesting, since ng-form is also a class directive:
<div class="control-group ng-form" name="controlGroup11" ng-class="{ error: controlGroup1.$invalid }>
<input ng-model="model1">
<input ng-model="model2">
</div>
Final solution Fiddle
Inside your link function, you can get access to the formController. It has all of the controls. So the following will give your directive access to .$valid:
el.controller('form')[attrs.errorOn].$valid
However, I don't know how to watch that for changes. I tried watching attrs.errorOn (i.e., watch the ng-model property), but the watch doesn't trigger unless a valid value is input (because of the way Angular forms work... unless that value is valid, it is not assigned to the scope property set by ng-model.)
Fiddle.
Maybe someone can take this further...

AngularJS: How do I bi-directionally bind to the parent scope property without using an attribute?

So I want to do what I did in this question:
AngularJS: Two way data binding fails if element has ngModel and a directive with a local scope
but without using an attibute value to bind. I've tried using just an equals sign
scope: {bindToParent: '='},
but it doesn't seem to work? Can someone change this jsfiddle: http://jsfiddle.net/ews7S/1/ to show me how I can directly bind to the parent property without having to use an attribute in the element?
You have in your fiddle:
<input type="text" ng-model="testModel" dir="123">
If you want dir to not have a value, well, dir doesn't need a value. This works as well in your fiddle:
<input type="text" ng-model="testModel" dir>

Resources