I try to hide my form after it has been 'submitted'. I want to do it with ng-if. Clicking on the button 'See' displays the form on and off, but it does not work on the button 'Add'. What is the reason for that?
I have created a JSFiddle. Link to JSFiddle.
My Form:
<form name="userAddForm" ng-submit="something()" class="form-horizontal" role="form">
<div class="form-group">
<label class="col-md-2 control-label">Username</label>
<div class="col-md-3">
<input name="username" ng-model="user.username" class="form-control" ng-required="true" placeholder="Username" type="text" />
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">Password</label>
<div class="col-md-3">
<input name="password" ng-model="user.password" class="form-control" placeholder="Password" type="password" ng-required="true" />
</div>
</div>
<button ng-disabled="userAddForm.$invalid" type="submit" ng-click="add=!add" class="btn btn-success">
<span class="glyphicon glyphicon-ok"></span> Add
</button>
</form>
</div>
Please, don't use $parent!
Use proper prototypal inheritance.
The reason it doesn't work is because you are creating a new scope through the usage of ngIf.
It does not create an isolate scope so you don't have to worry about that.
When you pass a primitive, Javascript will "shadow" that value on the prototype of the new scope.
As such, it is no longer a direct reference to the value in your parent scope.
How do you get around that?
add a dot
That roughly translates into; use an object and bind to a property of that object. objects don't get shadowed as they are not a primitive. you get to keep the reference and it just works™.
jsfiddle
Every directive in angularjs create different level of scope.So,there is different level of scope, one at form tag and one at button inside the form which create parent and child relationship between form and button inside it.As add is,primitive variable,its changes in child is not reflected in parent scope.
So,either use $parent service or define thet add variable in following way.
$scope.objHidShow = {};
$scope.objHidShow.add= false;
I would do it by calling a controller function:
$scope.something = function() {
$scope.shown = !$scope.shown;
}
What I did is to define that function and I made your controller working for the complete form.
https://jsfiddle.net/udc2rjrn/2/
The ng-if directive creates a new scope so you need to use $parent:
<button ng-disabled="userAddForm.$invalid" type="button" ng-click="$parent.add=!$parent.add" class="btn btn-success">
Updated JSFiddle
Related
I'm using ui-router and the view below accesses the controller using the 'Controller As' syntax. I'm adding the 'invalid' class onto the 'shift'-radios container. When form loads you can see both validation required messages (for requestDate and shift). When requestDate and shift are set validation messages disappear. Form's $valid is true. The only problem is that the 'invalid' class on the radio-wrapper div stays.
What am I doing wrong?
<form novalidate ng-submit="_form.$valid && formCtrl.getFormData()" name="_form">
<div class="datepicker-wrapper clearfix">
<datepicker date-format="yyyy-MM-dd">
<input required ng-model="formCtrl.requestDate" name="requestDate" type="text" />
</datepicker>
</div>
<div ng-messages="_form.requestDate.$error" role="alert">
<div ng-message="required">Введите дату</div>
</div>
<div class="radio-wrapper clearfix" ng-class="{invalid: _form.shift.$error}">
<div ng-repeat="shift in formCtrl.shifts" class="item half-width pull-left">
<label for="<% shift.name %>">
<input required ng-model="formCtrl.currentShift"
name="shift"
ng-value="shift"
id="<% shift.name %>"
type="radio" />
<span class="text"><span ng-bind="shift.text"></span></span>
</label>
</div>
</div>
<div ng-messages="_form.shift.$error" role="alert">
<div ng-message="required">Укажите смену</div>
</div>
<!-- other inputs... -->
</form>
I think you need to use the $invalid property, which is a boolean, instead of the $error property, which is a hash.
See: https://docs.angularjs.org/api/ng/type/ngModel.NgModelController
Your ng-class definition is checking the wrong property of the form controller. You are checking the truthyness of _form.shift.$error. This object will always exist, even if there are no validation errors. When you don't have any errors, the value of _form.shift.$error is empty object {} which is truthy.
You should instead check the _form.shift.$invalid property which will properly update whether there are any problems with that form field.
There is no _form.shift. The input shift is declared inside an ng-repeat so it is a property on the _form.
To fix you could for example, move your ng-class inside the ng-repeat and reference the shift using ng-form to create a sub-grouping:
<div ng-repeat="shift in formCtrl.shifts" ng-form='nestedShiftForm'>
<div ng-class="{invalid: nestedShiftForm.shift.$error}">
<input name="shift" />
I've never worked with Angular or Angular2 before, but now I have to make an update to a site running on my domain that is using Angular2. I need to programatically fill out a textbox and click submit, but after setting the textbox's value using .value = "val", it still treats the textbox as if it is empty.
I've read up on angular and now understand the concept of ng-dirty and ng-pristine, but programatically changing the class to ng-dirty still doesn't work.
It seems like even if I change the classes, it is still not updating the "pristine" status and it still considers the textbox empty.
I've read about "markAsDirty()" and tried using it but I get "markAsDirty is not a function". I just need to figure out how to update the page so that it realizes that the textbox is not empty and lets me submit the form.
Thanks a lot!
Edit:
Page form:
<form id="form_register" novalidate="">
<div class="form-steps">
<div class="form-group">
<div class="input-group">
<input autocomplete="off" class="form-control ng-pristine ng-invalid ng-touched" data-is-regex="true" data-mask="[a-zA-Z0-1\.]+" id="username" name="username" ngcontrol="username" placeholder="Username" required="" style="color: black !important;" tabindex="13" type="text">
</div>
</div>
<div class="form-group">
<div class="input-group">
<input autocomplete="off" class="form-control ng-untouched ng-pristine ng-invalid" id="password" name="password" ngcontrol="password" placeholder="Password" required="" style="color: black !important;" tabindex="14" type="password">
</div>
</div>
<div class="form-group">
<button class="btn btn-block btn-lg btn-info" tabindex="4" type="submit">
Log In
</button>
</div>
</div>
</form>
My problem is that this:
document.getElementById("username").value = "testuser";
document.getElementById("password").value = "testpass";
document.getElementsByClassName("btn btn-block btn-lg btn-info")[0].click();
ends up giving me a message saying the username and password are required even though there is a value showing in the textbox. Simply clicking on the textbox, typing a character, then deleting it will allow me to submit the form, but I need to accomplish this without user interaction.
You are filling the forms with native javascript and that is not updating the angular model. In your backing component you need to use ngmodel to connect your elements to the component. Then update the variables in the component and everything will reflect correctly.
Okay, there are a few issues with your code that I can see and I'll walk through getting this to work as expected.
For a Template driven form, create and assign the form group variable (which will make our shiny NgForm which we later attach controls to with ngControl) in the template, and lets bind the submit function while we're at it:
<form #myForm="ngForm" (ngSubmit)="submit(myForm.value)" id="form_register" novalidate="">
Each of our inputs is standalone and not yet tied to the form, to do so we'll want to clear the ng- classes which should be managed by Angular 2 and add our [(ngModel)] binding to a property.
<input autocomplete="off" class="form-control" data-is-regex="true" data-mask="[a-zA-Z0-1\.]+"
id="username" name="username" placeholder="Username" ngControl="username" [(ngModel)]="username"
required style="color: black !important;" tabindex="13" type="text">
We're going to disable our submit if the form is invalid:
<button [disabled]="myForm.invalid" class="btn btn-block btn-lg btn-info" tabindex="4" type="submit">Log In</button>
Our class has the username and password properties that we bind to, and our submit function:
export class App {
password: string;
username: string;
submit(value) {
console.log("submitting: " + JSON.stringify(value));
}
}
Finally, if we really want to mark things dirty programmatically this way we will have to grab our template variable in our code with a ViewChild:
#ViewChild('myForm') formGroup;
password: string;
ngAfterContentInit() {
this.formGroup.control.markAsDirty();
}
To do it per control we either need to access it through our formGroup variable or add individual template variables on the inputs we can grab with [(ngModel)]="username" #username="ngModel", for instance.
here's a plunker you can play with to try and develop your understanding: http://plnkr.co/edit/ukJ1kq2UFBvtoCsxbyba?p=preview
Say I have the following HTML...
<div class="row">
<div class="col-xs-3 align-right">
<p>Email</p>
</div>
<div class="col-xs-7">
<input type="text" class="form-control" ng-model="registrationForm.email.value"/>
<span class="error-label" ng-hide="registrationForm.email.valid"><span class="glyphicon glyphicon-remove"></span>Must be a valid email!</span>
</div>
</div>
This bit of HTML creates an email field, with an error label that is shown if the email provided is invalid. This works perfectly, and is not part of my question.
I would like to slightly alter the behavior of this label. When the user first visits the form, I don't want to display the error label unless the user has changed the value of the form input.
It seems like the $pristine and $dirty properties are the key, but I'm confused on how to go about using them. If I try to access them of properties of email.value (I.E. registrationForm.email.value.$pristine) the property seems to be undefined.
I would like to avoid enclosing these inputs in an HTML form. Is there still a way I can retain use of these properties, and if so, how?
When you create your <form> element, it will create a $scope variable with the name of your form. For example:
<form name="regForm">
<div class="row">
<div class="col-xs-3 align-right">
<p>Email</p>
</div>
<div class="col-xs-7">
<input type="text" class="form-control" name="email" ng-model="registrationForm.email.value"/>
<span class="error-label" ng-hide="registrationForm.email.valid"><span class="glyphicon glyphicon-remove"></span>Must be a valid email!</span>
</div>
</div>
</form>
You can access the $pristine using $scope.regForm.email.$pristine.
Without a <form>, simply use ng-form, which will give you the functionality of the form, without needing an actual <form> element. See this post for more information.
I am new to Angular. Please, consider the following piece of code.
<form name="newEventForm">
<fieldset>
<label for="eventName">Event Name:</label>
<input id="eventName" required ng-model="event.name" type="text" placeholder="Name of your event...">
<button ng-click="saveEvent(event, newEventForm)" type="submit" class="btn btn-primary">Save</button>
<button ng-click="cancelEdit()" type="button" class="btn btn-default">Cancel</button>
</form>
My question is - why do we need to pass the event argument to the saveEvent function? Doesn't using ng-model auto generate an event.name variable through two-way binding on the Angular side? e.g.
<form name="newEventForm">
<fieldset>
<label for="eventName">Event Name:</label>
<input id="eventName" required ng-model="event.name" type="text" placeholder="Name of your event...">
<button ng-click="saveEvent( newEventForm)" type="submit" class="btn btn-primary">Save</button>
<button ng-click="cancelEdit()" type="button" class="btn btn-default">Cancel</button>
</form>
In this second version of the code, I am not explicitly injecting event as a function parameter. However, when pressing submit, this is the code for saveEvent
$scope.saveEvent = function(newEventForm)
{
alert(1);
alert(newEventForm.$valid);
if(newEventForm.$valid)
{
window.alert('event ' + event.name + ' saved!');
}
}
and event is undefined. Shouldn't it be defined? Apologies if the question is a newbie's question. Just trying to get my head around how scope items are created through ng-model, and how does two-way binding work. Thanks !
UPDATE
Doh, I should've used $scope.event. Then it works. Thanks, like I said - new to this and it only dawned to me after I asked the question :)
The view is creating the event variable under the associated scope, use $scope.event.name.
Good luck
Actually all variable or model which are specified in the html are scope variable.
Example
<div ng-controller="myController" ng-init="name='Hello World'">
{{name}}
<button ng-click="myFn(name)"> Click Me </button>
</div>
In this example, I have initiated a variable called name. It is actually a scope variable. This code will actually like
myApp.controller("myController", function($scope){
$scope.name = "Hello World";
$scope.myFn = function(param){
// here you can see that your variable name passed from html is same as your scope variable
if(param == $scope.name){
alert("Yes, two are equal !!!");
}
}
});
This two are same. You can either use html or js.
I am trying to create custom elements which will convert my form elements to match bootstrap's form styling structure
Basically,
<my-input ng-model="myname">
should become
<div class="form-element">
<input ng-model="myname" />
</div>
The problem is that when I use transclude, the ng-model goes to the root element and the resulting DOM is
<div class="form-element" ng-model="myname">
<input>
</div>
Is it possible to choose which inner element the ng-model attribute is transferred to??
If I create another directive called my-model and use it instead of ng-model, how can I transfer this to the inner input element?
<my-input my-model="myname">
should become
<div class="form-element">
<input ng-model="myname" />
</div>
I think it is unnecessary to use ng-transclude here, you can simply have directive
<my-input model="myname">
and directive template
<div class="form-element">
<input ng-model="model" />
</div>
where directives scope is
scope: {
'model': '='
}
By using this you can have couple of models in directive and you can put them wherever you want.
Yes. I ran into this issue a little while ago.
You need to bind your ng-model as a property of an object such as.
<div class="form-element">
<input ng-model="user.myname" />
</div>
And in controller, make sure you do this.
$scope.user = {};
In this way, angular would be able to find the ng-model.