angularjs make div readonly - where to put business logic - angularjs

I want to make a section readonly based on a checkbox. Typical example is primary address and the billing address. The user enters primary address and can chose the billing address to be the same the primary address.
See fiddle for example.
HTML (primary address):
<fieldset ng-model="primaryAdd">
<legend>Primary Address:</legend>
House#: <input type="text" ng-model="primaryAdd.houseNum"><br>
Street: <input type="text" ng-model="primaryAdd.street"><br>
State: <input type="text" ng-model="primaryAdd.state"><br>
Zip: <input type="text" ng-model="primaryAdd.zip">
</fieldset>
HTML (Same as address)
<input type="checkbox" name="makeSameAsAddress" ng-model="makeSameAsAddressCheck" ng-click="makeSameAsAddress($event)">Same as above<br/>
HTML (Billing Address)
<fieldset ng-model="billingAddress">
<legend>Billing Address:</legend>
<div>
<div style="font-size:small">if the address is the same as residence, prefill and make it readonly</div>
House#: <input type="text" ng-model="billingAddress.houseNum" ng-readonly="makeSameAsAddressCheck"><br>
Street: <input type="text" ng-model="billingAddress.street" ng-readonly="makeSameAsAddressCheck"><br>
State: <input type="text" ng-model="billingAddress.state" ng-readonly="makeSameAsAddressCheck"><br>
Zip: <input type="text" ng-model="billingAddress.zip" ng-readonly="makeSameAsAddressCheck">
</div>
</fieldset>
The fiddle does work. When I click on "Same as above" checkbox, the billing section gets the address from the primary section and is readonly. The question is why I cannot put the ng-readonly on the fieldset or the div surrounding the inputs. I have to put the ng-readonly on all the inputs. I feel like there must be a better way to do this.
Maybe I need to create a directive called "makeSameAsPrimaryAndReadOnly". I read that business logic should sit in directives and not HTML directly or the controllers. But I don't see the point of doing this. Unless I was reusing the billing address in multiple places.
Secondly, where is a good place to initialize the model and have a schema to share with other controllers etc? I imagine a factory would be best for this? Thank you.
Angular rocks !!

You could create a directive, but it might be overkill for this purpose.
You can't apply the ng-readonly to the div or the fieldset like it were a css style. Honestly, I don't think it's too bad the way it is if you only have 4 inputs.
You can simplify the logic for the checkbox (and eliminate the ng-click event) by using a watch expression:
$scope.$watch('makeSameAsAddressCheck', function (newv, oldv) {
if (newv)
$scope.billingAddress = $scope.primaryAdd;
else if (newv !== oldv)
$scope.billingAddress = angular.copy($scope.primaryAdd);
});
Notice that when you turn the checkbox on, I set both scope variables to reference the same object. Now when you make modifications to the primary address, it's automatically updated in the billing address.
When you turn the checkbox off, I make a copy of the primary address. They can now be edited independently.
http://jsfiddle.net/fcSgz/
Business login in controllers is fine. In fact, that's where it should be.
You can initialize your model in a service, which is created with the "factory" function.

Related

Relative model reference?

I'm writing a few components for a form, these will be included (via Grails <g:include> tags) in multiple places (a registration page, and an account page). The way Angular works, I have to specify the form name in order to get a reference to a particular field. For example:
<form name="myForm">
<input ng-model="username"/>
{{myForm.username}} -- right here
</form>
In the example above, I must use myForm in order to access username. This will not work when using the same field in multiple forms, as the form name will change.
Is there a way to access the field relatively, or maybe figure out the enclosing form name and inject that?
You shouldn't have to reference your form's name. Just bind it to a property on your controller's $scope and you should be good to go. Doing it this way, you won't have to care what your form name is, only that the controller has the property you need.
<form ng-controller="yourController">
<input ng-model="username"/>
{{ username }}
</form>
angular.controller('yourController', ['$scope', function($scope){
$scope.username = 'keanu reeves';
}]);
Here's a code pen.
You have to use some sort of dynamic form name code. e.g.
<div ng-repeat="myForm in forms">
<form name="myForm{{$index}}">
<input ng-model="myForm.username"/>
{{myForm.username}} -- right here
</form>
</div>
Although it's difficult to solve your exact problem without example code. Create a plunker or codepen that we can analyze.

Few queries about form validation by Angular js

i am new in angular and trying to learn it.
https://scotch.io/tutorials/angularjs-form-validation
https://scotch.io/tutorials/angularjs-form-validation-with-ngmessages
i was reading article on form validation by angular js and i stumble in few area which i would like to discuss here.
1) what is difference between $pristine and $dirty. both looks same.
2) need to understand $touched? what it does ?
3) see the below code
<div class="form-group">
<label>Name</label>
<input type="text" name="name" class="form-control" ng-model="name" required>
</div>
<!-- USERNAME -->
<div class="form-group">
<label>Username</label>
<input type="text" name="username" class="form-control" ng-model="user.username" ng-minlength="3" ng-maxlength="8">
</div>
for first one ng-model="name" and second one ng-model="user.username"
why some time only property name declared for ng-model and why some time we have to write username dot property name ?
4) <input type="email" name="email" class="form-control" ng-model="email">
type="email" is anything specific to angular or html5?
5) <p ng-show="userForm.name.$invalid && !userForm.name.$pristine" class="help-block">You name is required.</p>
they check $invalid and $pristine. can they use $invalid and $dirty instead of $pristine here ?
6) see the code
angular
.module('app', ['ngMessages'])
.controller('MainCtrl', MainCtrl);
function MainCtrl() {
}
are they injecting other directive into app module....this is the way to inject
.module('app', ['ngMessages'])
please see my points and guide me with answer for my each points if possible. your answer would help me to understand and learn angular js.thanks
1) $pristine is for indicating that the field has not been modified, whereas $dirty is for telling it has been modified.
$pristine: It will be TRUE, if the user has not interacted with the form yet.
$dirty: It will be TRUE, if the user has already interacted with the form.
2) $touched tells you whether the user has merely been there/visited.
$touched: True if control has lost focus.
3) because for ng-model="name", name property is directly bound to $scope, and for ng-model="user.username", user is bound to $scope and user has a property username.
Think of it as:- user is an object and username is its property.
4) Not sure, but i think not anything specific.
5) Yes
6) Yes here you are injecting ngMessages in your angular module
$pristine is the inverse of $dirty.
The documentation says: A model is considered to be touched when the user has first focused the control element and then shifted focus away from the control (blur event)..
Because some time you want to bind the control to a variable in the scope, and sometimes you want to bind it to a field of an object that is in the scope. The latter is recommended. In particular, the former causes problems when used inside a directive (like ng-if or ng-repeat) that has its own scope, because it would set the field in the child directive scope instead of the controller scope. As a rule of thumb, always use the latter, and always initialize the object (i.e. user) in the controller.
it's both. It's specified in the HTML5 spec, and angular validates that the entered string is indeed a valid email address.
yes, since $dirty is the inverse of $pristine
That doesn't inject anything. 'ngMessages' is the name of a module. This declaration says that the module 'app' depends on the module 'ngMessages'. So all the directives, services, controllers and filters defined in the ngMessages module will be available in the app module.

AngularJS ng-required better implement from controller?

I'm thinking of a good way to implement ng-required.
Let's say I have a bunch of inputs with ng-required in my app.
<input type="text" id="one" />
<input type="date" id="two" />
<input type="radio" id="three" />
<input type="checkbox" id="four" />
I would like to do something in a controller, where I could pass an array of required fields. I'm thinking that if I made an array of elements such as:
var myEl = angular.element( document.querySelector( '#some-id' ) );
and some how set the required property that way.
I write a directive which would decide from an array if the field is required, if it does not exist in the array, it's not required if it does, it's required.
Ultimately, I would like to have an array that allows passing of fields in such a way:
var reqArray = ('#id', ('#id1' || 'id2')) etc.
Works the same as conditional logic operators:
#id is required
#id1 || #id2 is required, but not both.
Not sure where to begin, or if it's feasible in Angular.
This would make it easier to modify required fields in large applications without having to modify the actual html.
It can be done, but angular already provides its own ways to validate forms. Some brief details:
The form tag must have a novalidate attribute in order to prevent HTML5 validation. <form name="myForm" novalidate>
With that, now angular can take charge of the validation by adding a "required" attribute to your inputs <input ng-model="myModel" type="text" required>
By this point, angular has taken control of your validation, it can also validate other HTML5 attributes like pattern. <input pattern="[0-9][A-Z]{3}" type="text" title="Single digit followed by three uppercase letters."/>
I suggest you take look at this official guide (also take a look at the directives guide on that same site, I wanted to link it but I don't yet have the rep).
That being said, what you are trying to accomplish is also possible, but rather redundant since you would have to add an attribute to your inputs anyway (the directive, and angular is able to validate already) and also require ngModel in the directive.
I made this plunkr to show you how to do it, but take notice of the extra work needed in order to validate something that angular already does natively, I'd leave this kind of work for expanding on validations, like comparing items or models.
Also, querying a selector directly like in your suggestion is not considered "the angular way". A better way would be to add the directive to your form element and access the element through the 'element' parameter in the directive.
Hope this helps.

Angular.js sanity check: Services vs. Factories vs. Controllers... + Directives + Behavior

This article about when to use directives, services and controllers, as awesome and helpful as it is... has me massively confused about everything I think I know about the ideal structure of an angular application and I just need a sanity check:
If you have two inputs:
<label><span>false</span>
<input type='radio' value='false' ng-value='false' ng-model='thing.exists' />
</label>
<label><span>true</span>
<input type='radio' value='true' ng-value='true' ng-model='thing.exists' />
</label>
that are part of a larger form, which will in turn submit to pull in another form... and that information will later be shown for review, is this the correct way to architect that:
TLDR: Flow of execution:
ng-model="thing.exist" ==> thing ==> ThingController ==> a service ==> ...details... ==> getDetails?
Right now I have:
<div ng-controller='ThingController as thing'>
<fieldset>
<label><span>Doesn't exist</span>
<input type='radio' value='false' name='checkExist'
ng-value='false' ng-model='thing.exists' />
</label>
<label><span>Does exist</span>
<input type='radio' value='true' name='checkExist'
ng-value='true' ng-model='thing.exists' />
</label>
</fieldset>
<!-- ... -->
</div>
When the input changes,
I should use ng-change on the inputs to trigger the behavior (like the addition of a directive)... right (via a controller)?
I should use then controller to add the result of the ng-change to a service? Like... passing the model value (thing.exists) to a service so I can use that value later?
As a complication factor- this application uses Require.js to manage dependencies.
(Actually, the article itself isn't the source of my confusion- it's the comments on the article that are killing me.)
That's pretty much it, you've got it right. The idea is the following:
Use directives for managing user interface interactions and -some- state changes
Use controllers for managing a shallow set of logic
Use services for sharing data, functionality and business logic.
Aka, just like on your server - try not to load too much into a controller.

One form element updating multiple pieces of the model?

I am looking at using angular for a project at work but I have a question first. We have a single page application that's pretty intricate. We do have a basic model set up but some fields in the model are redundant. If I couldn't reduce the redundancy, what steps could I take in angular so that one form element changes two variables in the model?
I've put together a bare bones jsfiddle of what I'm hoping to do:
<div ng-app>
<input type="text" ng-model="yourName" placeholder="Enter a name here" /><br/>
<span>Hello {{yourName}}!</span><br/>
<span>Hello {{altName}}!</span>
</div>
How could I change this around so that the input would assign it's value to both yourName as well as altName? I've tried what I thought would be obvious such as comma or pipe delimiting the ng-model attribute to no avail. Is it possible?
You could set a $watch on the yourname-Variable within your controller and then change the altName in its callback. Should look like this:
$scope.$watch('yourName', function(){
$scope.altName = $scope.newName;
});

Resources