How can I isolate nested form? - html

I'm very new to AngularJS, and new to client side programming.
Context:
I'm implementing a contact form with support for multiple phone numbers and addresses.
It look like this:
<form name="contactInsertForm" ng-controller="contactInsertController as contactCtrlr" ng-submit="contactInsertForm.$valid && contactCtrlr.save()">
<input type="text" name="name" />
<phones-editor></phones-editor>
<addresses-editor></addresses-editor>
<input type="submit" />
</form>
phonesEditor and addressesEditor are custom Angular directives which implement support for adding, removing and editing phones and addresses. The controllers and modules look like this:
Addresses:
(function () {
var app = angular.module("AddressesEditorModule", []);
app.directive("addressesEditor", function () {
return {
restrict: "E",
templateUrl: "/addressesEditorTemplate.html",
controller: function ($scope) {
this.addresses = [
// this will hold addresses.
];
// ...
}
}
})();
Phones:
(function () {
var app = angular.module("PhonesEditorModule", []);
app.directive("phonesEditor", function () {
return {
restrict: "E",
templateUrl: "/phonesEditorTemplate.html",
controller: function ($scope) {
this.phones = [
// this will hold phones.
];
// ...
}
}
})();
And the templates:
Addresses:
<!-- list already added addresses -->
<div ng-repeat="address in addressesEditorCtrlr.addresses">
<p>{{address.address}}</p>
<p>{{address.city}}</p>
</div>
<form name="addressInsertForm" ng-submit="addressInsertForm.$valid && addressesEditorCtrlr.add()">
<!-- inputs for each of the address fields -->
<input type="submit" value="Add" />
</form>
Phones:
<!-- list already added phones -->
<div ng-repeat="phone in phonesEditorCtrlr.addresses">
<p>{{phone.number}}</p>
<p>{{phone.areaCode}}</p>
</div>
<form name="phoneInsertForm" ng-submit="phoneInsertForm.$valid && phonesEditorCtrlr.add()">
<!-- inputs for each of the phone fields -->
<input type="submit" value="Add" />
</form>
As you may have noticed, the generated at the browser HTML looks like this:
<form>
<input type="text" name="name" />
<phones-editor>
<!-- list already added phones -->
<div ng-repeat="phone in phonesEditorCtrlr.addresses">
<p>{{phone.number}}</p>
<p>{{phone.areaCode}}</p>
</div>
<form name="phoneInsertForm" ng-submit="phoneInsertForm.$valid && phonesEditorCtrlr.add()">
<!-- inputs for each of the phone fields -->
<input type="submit" value="Add" />
</form>
</phones-editor>
<addresses-editor>
<!-- list already added addresses -->
<div ng-repeat="address in addressesEditorCtrlr.addresses">
<p>{{address.address}}</p>
<p>{{address.city}}</p>
</div>
<form name="addressInsertForm" ng-submit="addressInsertForm.$valid && addressesEditorCtrlr.add()">
<!-- inputs for each of the address fields -->
<input type="submit" value="Add" />
</form>
</addresses-editor>
</form>
The problem:
I have two form's inside a form. The nested forms work correctly, adding and validating values it should be doing, and refusing to add invalid phones/addresses.
But when I click the submit button at the outer form, it will interpret the inner forms input fields and will raise errors if these fields have invalid values.
How can I use AngularJS form handling and avoid this situation? Is this possible at all?

you would need a directive if you want child form as isolate form. Have a look at answers from this SO question. please have a look at fiddle attached in this answer. I am putting the fiddle link here for you to js-fiddle to see it in action.
putting below code just because SO doesnt accept only fiddle links...
<form name="parent">
<input type="text" ng-model="outside"/>
<ng-form name="subform" isolate-form>
<input type="text" ng-model="inside"/>
</ng-form>
</form>

Working on Angular 1.6
const isolatedFormDirective = () => {
return {
restrict: 'A',
require: '?form',
link: ($scope, $element, $attrs, ctrl) => {
ctrl && ctrl.$$parentForm && ctrl.$$parentForm.$removeControl(ctrl);
}
}
}
app.directive('isolatedForm', isolatedFormDirective);

This article has exactly what you are looking for.
The basic gist is that you want to use the ngForm directive inside your form tag.
<div ng-form="outerForm">
<input type="text" ng-model="main.outerFormText"/>
<div ng-form="innerForm">
<input type="text" ng-model="main.innerFormText" required/>
<button type="button" ng-click="main.submit('innerForm')"
ng-disabled="innerForm.$invalid">Inner Submit</button>
</div>
<button type="button" ng-click="main.submit('outerForm')"
ng-disabled="outerForm.$invalid">Outer Submit</button>
</div>
Example plnkr

Related

How to change fieldset with form to textarea triggable by a button?

I have this code that needs to be adapted to work with something similar to the code below the commented line. If I can make it without many changes would be perfect so that I don't need to change the CSS and so. Any help? Many thanks in advance.
<!-- The code to be adapted is this: -->
<form action="" id="search-form">
<fieldset>
<input type="text" class="text" /><input type="submit" value="Search" class="submit" />
</fieldset>
</form>
<!-- The new code that I got from the web and that needs to be adapted to the old one
is the following: -->
<textarea id="Blah"></textarea><button onclick="search()">Search</button>
<script>
function search() {
var Blah = document.getElementById("Blah").value;
location.replace("https://www.google.com/search?q=" + Blah + "");
}
</script>
I'm imagining you probably want something like
document.querySelector("#searchButton").addEventListener("click", ()=>{
const value = document.querySelector("#searchBox").value;
const url = `https://www.google.com/search?q=${encodeURIComponent(value)}`;
window.location.replace(url);
});
<fieldset>
<input type="text" class="search" id="searchBox">
<Button id="searchButton">Search</button>
</fieldset>
The id attribute on HTML elements allows you to access them via JavaScript. There's a wealth of tutorials online if you want to learn JavaScript deeply, but the basics of what this is doing is:
It finds the HTML element with the id of searchButton, and adds a click listener to it --- this gets triggered whenever that element is clicked.
In that listener, we find the value of the text input with the id of searchBox.
We compose our new URL. One thing I've added here is a call to encodeURIComponent to correctly handle the cases where they try searching for something which contains a character which isn't valid in a URL --- for example, the space character etc.
It was not working as I wanted, but a little trick made it work.
Here is my final code:
<form action="" id="search-form">
<fieldset>
<input type="text" class="search" id="searchBox">
<input type="submit" value="Search" class="submit" />
</fieldset>
</form>
<script>
let myvar;
document.querySelector(".submit").addEventListener("click", ()=>{
const value = document.querySelector("#searchBox").value;
myvar = `https://www.google.com/search?q=${encodeURIComponent(value)}`;
setTimeout(callurl, 1);
return false;
});
function callurl() {
location.assign(myvar);
return false;
}
</script>

Unable to get ng-message to disappear when form is valid or reference form in controller

I know this question has been asked many times but none of the answers/resources have been able to help me.
I am trying to make a simple form in angular that will take a number and display a message if it is negative:
<div layout-padding ng-controller="BaseController as vm">
<form name="vm.mechanicalForm">
<input type="number" min="0" name="test" ng-model="vm.building.numberOfChillers" required />
<div ng-messages="vm.mechanicalForm.number.$error">
<div ng-message="min">
Test worked
</div>
</div>
<input type="button" ng-click="vm.save()" value="Save" />
</form>
Additionally, when I save the form, I want the controller to log one message if the form is valid, and another if it is not valid:
var app = angular.module('plunker', ['ngMessages']);
export class BaseController {
public mechanicalForm;
public building;
constructor() {
this.mechanicalForm = {};
this.building = {
'numberOfChillers': 0
};
}
public save() {
if (this.mechanicalForm.$valid) {
console.log("This worked");
}
else {
console.log("This did not work");
}
}
}
app.controller('BaseController', BaseController);
But it seems like my controller is not able to see the form at all. According to everything I have read I seem to be writing the code correctly. My two questions are:
1: Why will the ng-message not disappear when my input is valid?
2: Why is my controller not able to see my form object?
Here is a code pen Demonstrating my issue. I am using AngularJS 1.5.3
For reference, here are the resources I have referred to so far:
How to use ng-messages
AngularJS form and control state
Using 'controller as' syntax
common issues with ng-messages
<div layout-padding ng-controller="BaseController as vm">
<form name="vm.mechanicalForm">
<input type="number" min="0" name="test" ng-model="vm.building.numberOfChillers" required />
̶<̶d̶i̶v̶ ̶n̶g̶-̶m̶e̶s̶s̶a̶g̶e̶s̶=̶"̶v̶m̶.̶m̶e̶c̶h̶a̶n̶i̶c̶a̶l̶F̶o̶r̶m̶.̶n̶u̶m̶b̶e̶r̶.̶$̶e̶r̶r̶o̶r̶"̶>̶
<div ng-messages="vm.mechanicalForm.test.$error">
<div ng-message="min">
Test worked
</div>
</div>
<input type="button" ng-click="vm.save()" value="Save" />
</form>
The DEMO on PLNKR

Angular Form Undefined In Controller

Have an angular form that I'm passing into my controller.
When I open browser to inspect form, it is undefined. I've tried changing the name of the form, and moving the form tag to enclose the entire body. Here is my form:
<form layout-padding id="form-container" ng-controller="RegisterController as RgCtrl" layout="column" ng-cloak name="projectForm">
<div id="content-row-header">What is your email?</div>
<md-input-container class="md-block md-input-focused">
<label>Email</label>
<input required type="email" name="email" ng-model="email"
minlength="10" maxlength="100" ng-pattern="/^.+#.+\..+$/" />
<div ng-messages="projectForm.email.$error" role="alert">
<div ng-message-exp="['required', 'minlength', 'maxlength', 'pattern']">
Your email must be between 10 and 100 characters long and look like an e-mail address.
</div>
</div>
</md-input-container>
<div id="content-row-header">Set a password</div>
<md-input-container class="md-block md-input-focused">
<label>Password</label>
<input required name="password" ng-model="password">
<div ng-messages="projectForm.password.$error">
<div ng-message="required">This is required.</div>
</div>
</md-input-container>
</form>
Here is my function call:
<md-button id="orange-button" ui-sref="app.unauthenticated.purchase.agent" ng-click="doRegistration(projectForm)" flex>Create Account</md-button>
and here is my controller:
(function () {
'use strict';
angular
.module('app.auth.register')
.controller('RegisterController', RegisterController);
/** #ngInject */
function RegisterController($scope, $auth, $log, $location,$rootScope,$state,app_auth,$stateParams) {
// Data
var vm = this;
// Methods
$scope.doRegistration = function (form) {
console.log(form);
app_auth.register(form.email.$viewValue,form.password.$viewValue,form.passwordConfirm.$viewValue);
};
// $scope.goHome = function () {
/
/ $state.go('app.public');
// };
}
})();
right now when that console.log(form) runs, form is undefined
If you have some conditional directive in the form:
<form name="myForm" ng-if="someVariable">
Then $scope.myForm will be undefined in your controller.
Besides, you should use ng-submit.
you are using a directive.
The directive scope is different from the controllers. That's why you are not able to see the form reference.
GO to directive implementation and add:
scope: {
projectForm: '=',
},
reference: https://www.sitepoint.com/form-based-directives-angularjs/
name attribute will bind form controller to $scope, so you have name="projectForm" in your controller you should be able
to use $scope.projectForm
check jsfiddle here
https://jsfiddle.net/hurricanew/6tqywue6/
Register Controller had to encompass the form definition and function that took in a form as argument

ng-model vs ngModel - breaks form

New to angular, new to life:
I have a small email form.
This works:
<form method="post" name="form" role="form" ng-controller="contactForm" ng-submit="form.$valid && sendMessage(input)" novalidate class="form-horizontal">
<p ng-show="success"><b>We received your message</b></p>
<p ng-show="error">Something wrong happened!, please try again.</p>
<label for="name">Name:</label><br>
<input type="text" id="name" name="name" ng-model="input.name" required><br>
<label for="email">Email:</label><br>
<input type="email" id="email" name="email" ng-model="input.email" required><br>
<label for="messsage">Message:</label><br>
<textarea id="messsage" name="message" ng-model="input.message" ngMaxlength='2000' required></textarea><br>
<button type="submit" name="submit" ng-disabled="error" value="submit">Submit</button>
</form>
This does not work:
<form method="post" name="form" role="form" ng-controller="contactForm" ng-submit="form.$valid && sendMessage(input)" novalidate class="form-horizontal">
<p ng-show="success"><b>We received your message</b></p>
<p ng-show="error">Something wrong happened!, please try again.</p>
<label for="name">Name:</label><br>
<input type="text" id="name" name="name" ngModel="input.name" required><br>
<label for="email">Email:</label><br>
<input type="email" id="email" name="email" ngModel="input.email" required><br>
<label for="messsage">Message:</label><br>
<textarea id="messsage" name="message" ngModel="input.message" ngMaxlength='2000' required></textarea><br>
<button type="submit" name="submit" ng-disabled="error" value="submit">Submit</button>
</form>
for the 2 inputs and the textarea if I use 'ng-model' the email sends, but when the page loads, the form loads invalid.
If i use 'ngModel' the form loads clean, but the email wont submit.
controller here:
app.controller("contactForm", ['$scope', '$http', function($scope, $http) {
$scope.success = false;
$scope.error = false;
$scope.sendMessage = function( input ) {
$http({
method: 'POST',
url: 'processForm.php',
data: input,
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
})
.success( function(data) {
if ( data.success ) {
$scope.success = true;
$scope.input.name="";
$scope.input.email="";
$scope.input.message="";
} else {
$scope.error = true;
}
} );
}
You can see it live here:
http://smartestdiner.com/Bethel/indexx.html#/contact
Warning:
There is some annoying red background
.ng-invalid{
background-color:red;
}
}]);
That's how we know it is loading invalidly.
The annoying red background is the form, since you have a very generic rule set by .ng-invalid, the class will be set on the form as well. You would need to make it more specific for the inputs and controls within the form.
Example:
input.ng-invalid,
textarea.ng-invalid {
background-color:red;
}
Or just reset rule for form.ng-invalid
To add on there is nothing called ngModel it is ng-model. using the former one doesn't do anything but adds a dummy attribute on the element, it has no effect. It is angular way of directive naming, since html is case insensitive the one way angular can identify the directive from attribute or element name (based on the restriction). It converts it to camelCasing to evaluate and process respective directive (or directives attribute bindings). When you do not have ng-model specified and if the form or control does not have novalidate attribute, then the browser's HTML5 validation kicks in that is what you see as inconsistency. Using HTML5 novalidate attribute makes sure no native validation happens on the form.
ng-model is when u write the view (html part).
ngModel is used when one write a custom directive. It is placed in the "require:" param so that u can access,
variables like ngModel.$modelValue
ngModel.$modelValue will have the latest content which has been typed by the user at realtime. So, it can be used for validations, etc.
View code:-
<!doctype html>
<html ng-app="plankton">
<head>
<script src="/bower_components/angular/angular.min.js"></script>
<script src="/scripts/emailing/emailing.directive.js"></script>
</head>
<body ng-controller="EmailingCtrl">
<div>
<label>Enter Email: </label>
<emailing id="person_email" ng-model="email_entered"></emailing>
</div>
</body>
</html>
Custom directive:-
(function() {
'use strict';
angular.module('plankton', [])
.directive('emailing', function emailing(){
return {
restrict: 'AE',
replace: 'true',
template: '<input type="text"></input>',
controllerAs: 'vm',
scope: {},
require: "ngModel",
link: function(scope, elem, attrs, ngModel){
console.log(ngModel);
scope.$watch(function(){ return ngModel.$modelValue;
}, function(modelValue){
console.log(modelValue);//awesome! gets live data entered into the input text box
});
},
};
})
.controller('EmailingCtrl', function($scope){
var vm = this;
});
})();
This has been plunked here:- here

html forms, input leads to certain webpage

i'm not a very good programmer at all but i need a little help with a webpage i'm making.
Here's what I have for a form:
<form name="input" action="name.htm" method="get">
Name: <input type="text" name="name">
<input type="submit" value="Submit">
</form>
What I want it to do is if I put in the name Fred and press submit Button, it will go to a certain page. Any other name will link to another page or popup with an error saying, "tough luck!" or something like that.
Sorry, I couldn't find anything this specific on the web anywhere. I'm sure it's simple, I'm just confused with how this works. Thank you!
using front-end only, i'd be using javascript or jquery. meaning you don't need a form element inside it.
<script>
$("#submitButton").click(function(){
window.location.replace("enter url here")
})
</script>
you can do it with JS/jQuery:
HTML
<form name="input" action="name.htm" method="get">
Name: <input type="text" name="name" id="name">
<input type="submit" id="submit-button" value="Submit">
</form>
JS
$("#submit-button").click(function(){
if ($("#name").val() == "Fred")
location.href = "goodurl";
else
location.href = "badurl";
});
There are 2 options to solve this problem.
To use JavaScript for input value's validation and depending on it to redirect user
To use server side language to check the passed value
The first option will be easier for you I guess.
You can do something like:
Name: <input type="text" name="name">
<input type="button" value="Submit" onClick="redirect();">
<script type="text/javascript">
function redirect() {
var value = document.getElementsByName('name')[0].value;
if (value == 'Fred') {
window.location.href='http://url1';
} else {
window.location.href='http://url2';
}
}
</script>
Links: 'url1' and 'url2' must be replaced with your URLs
Just add the following code in your HTML file and try it out:
<script type="text/javascript">
function handleSubmit() {
var name = document.input.name.value;
if(name == 'Fred') {
location.href = "http://www.google.com";
} else if (name == 'Jack') {
location.href = "http://www.yahoo.com";
} else {
alert("Tough Luck");
}
}
</script>
<form name="input" action="name.htm" method="get">
Name: <input type="text" name="name">
<input type="button" value="Submit" onclick="handleSubmit();">
</form>