I've something weird going on here with Angular.
I have a details view with an edit button. When I press the edit button, I pass the object to the edit view. On the edit form there are a few dropdown boxes. The first time I click the edit button, everything loads well. All the dropdowns has the correct value selected. When I press cancel on the edit form, I get back to the details view. When I do nothing and press the Edit button again on the details view, the dropdowns don't have selected values at all! However the dropdowns do have items.
How is this possible? I didn't do anything with the data!
The details view and edit view are both directives:
In the template of customerDetails:
<div>
Here all the details of the customer
<button ng-click="ShowCustomerEditForm()">Edit</button>
</div>
<customer-edit
visible="showCustomerForm"
customer = "customer">
</customer-edit>
directive customer-edit:
app.directive("customerEdit", function (CustomerService, CountryService) {
return {
restrict: 'E',
templateUrl: '/Customer/Add',
scope: {
customer: '=',
visible: '=',
onCustomerSaved: '&'
},
link: function (scope, element, attributes) {
CustomerService.getAllAcademicDegrees().then(function (response) {
scope.academicDegrees = response;
});
CustomerService.getAllGenders().then(function (response) {
scope.genders = response;
});
CountryService.getAllCountries().then(function (response) {
scope.countries = response;
});
scope.$watch('customer', function (newValue) {
if (newValue && newValue.Id > 0) {
scope.customer.originalCustomer = {};
angular.copy(scope.customer, scope.customer.originalCustomer);
}
});
scope.customerFormSubmit = function () {
if (scope.customer.Id > 0) {
editCustomer();
}
else {
addCustomer();
}
}
scope.hideCustomerForm = function (restoreOriginal) {
if (restoreOriginal) {
angular.copy(scope.customer.originalCustomer, scope.customer);
}
scope.visible = false;
}
// Private functions
function editCustomer() {
var editCustomer = createCustomer(scope.customer);
editCustomer.Id = scope.customer.Id;
CustomerService.editCustomer(editCustomer).then(editCustomerSucceeded);
scope.hideCustomerForm(false);
}
function editCustomerSucceeded(response) {
var uneditedCustomer = _.findWhere(scope.customers, { Id: response.Id });
angular.copy(response, uneditedCustomer);
}
function addCustomer() {
var newCustomer = createCustomer(scope.customer);
CustomerService.addCustomer(newCustomer).then(function (response) {
scope.onCustomerSaved({ customer: response });
scope.hideCustomerForm(false);
});
}
}
}
});
I am trying to fix this for 6 hours now and I just don't understand it and I'm getting very desperate.. I just don't know how to fix this and what's causing this. I really hope someone can help me..
edit:
The customer edit html:
<div class="add-edit-container">
<div class="titleBox">
{{ customerFormData.title }}
<span class="close" title="Annuleren en sluiten" ng-click="hideCustomerForm(true)">×</span>
</div>
<div class="border">
<form id="frmAddCustomer" name="form" novalidate data-ng-submit="customerFormSubmit()">
<div>
<fieldset>
<legend>Identificatie</legend>
<label>Code:</label>
<input type="text" data-ng-model="customer.Code" />
<label>Geslacht:</label>
<label style="float: left;margin-right: 3px;" data-ng-repeat="gender in genders" data-ng-hide="$first">
<input type="radio" name="gender" data-ng-value="gender" data-ng-model="customer.Gender" />{{gender.Description}}
</label>
<div class="clear-float"/>
<label>Titel:</label>
<select data-ng-model="customer.AcademicDegree" data-ng-options="degree.Description for degree in academicDegrees"></select>
<label>Initialen:</label>
<input type="text" required data-ng-model="customer.Initials" />
<label>Voornaam: </label>
<input type="text" required data-ng-model="customer.FirstName" />
<label>Tussenvoegsel:</label>
<input type="text" data-ng-model="customer.MiddleName" />
<label>Achternaam:</label>
<input type="text" required data-ng-model="customer.LastName" />
<label>Geboortedatum:</label>
<input type="text" datepicker="01-01-1950" required data-ng-model="customer.BirthDate" />
<label>BSN:</label>
<input type="text" required data-ng-model="customer.BSNNo" />
<label>Identificatienummer:</label>
<input type="text" required data-ng-model="customer.IdCardNo" />
</fieldset>
<fieldset>
<legend>Contact</legend>
<label>Straat:</label>
<input type="text" required data-ng-model="customer.Street" />
<label>Huisnummer + toevoeging:</label>
<input type="text" required data-ng-model="customer.HouseNumber" style="width: 50px"/>
<input type="text" data-ng-model="customer.HouseNumberAddition" style="width: 50px"/>
<label>Postcode:</label>
<input type="text" required data-ng-model="customer.ZipCode" />
<label>Woonplaats:</label>
<input type="text" required data-ng-model="customer.City" />
<label>Telefoonnummer overdag:</label>
<input type="text" required data-ng-model="customer.DayPhone" />
<label>Telefoon anders:</label>
<input type="text" data-ng-model="customer.PhoneOther" />
<label>E-mailadres:</label>
<input type="email" required data-ng-model="customer.EmailAddress" />
<label>Bedrijfsnaam:</label>
<input type="text" data-ng-model="customer.CompanyName" />
<label>Land:</label>
<select data-ng-model="customer.Country" data-ng-options="country.Description for country in countries"></select>
</fieldset>
<fieldset>
<legend>Afwijkend postadres</legend>
<label>Straat:</label>
<input type="text" data-ng-model="customer.OtherStreet" placeholder="leeg indien niet van toepassing" />
<label>Huisnummer + toevoeging:</label>
<input type="text" data-ng-model="customer.OtherHouseNumber" style="width: 50px"/>
<input type="text" data-ng-model="customer.OtherHouseNumberAddition" style="width: 50px"/>
<label>Postcode:</label>
<input type="text" data-ng-model="customer.OtherZipCode" placeholder="leeg indien niet van toepassing" />
<label>Woonplaats:</label>
<input type="text" data-ng-model="customer.OtherCity" placeholder="leeg indien niet van toepassing" />
<input type="hidden" data-ng-model="customer.OtherAddressId" />
</fieldset>
</div>
<div class="button-box">
<input type="submit" value="Opslaan" class="button" />
Annuleren
</div>
</form>
</div>
</div>
I can answer why this problem is happening.
The problem is:
angular.copy(scope.customer.originalCustomer, scope.customer);
angular.copy does a deep copy. After the above call, scope.customer.Country, for instance, is a brand new object, it's not an element of scope.countries anymore. Therefore, the select directives lost track of the selected values.
Related
Example Form So Far
This is my current code that works, without any checkbox handling started.
import React, { useState } from "react";
import "../admin/SysHealthForm.scss";
export default function SysHealthForm() {
const [input, setInput] = useState({
header: "",
content: "",
eta: "",
});
//When any change is registered, update the Name + Value with target.
//Return previous text and display as name: entered value
function handleChange(e) {
const { name, value } = e.target;
setInput((prevInput) => {
return {
...prevInput,
[name]: value,
};
});
}
//Stop Page Refreshing and Console.log the JSON
function handleClick(e) {
e.preventDefault();
console.log(input);
}
return (
<div className="widgit-syshealth">
<h2>System Health</h2>
<form>
<input
name="header"
placeholder="Header"
autoComplete="off"
onChange={handleChange}
value={input.header}
required
></input>
<textarea
name="content"
placeholder="Message"
autoComplete="off"
onChange={handleChange}
value={input.content}
required
></textarea>
<div className="form-school-check">
<div>
<input type="checkbox" id="syshpcb1" value="Fosseway"></input>
<label htmlFor="syshpcb1">Fosse Way</label>
</div>
<div>
<input type="checkbox" id="syshpcb2" value="Mendip"></input>
<label htmlFor="syshpcb2">Mendip</label>
</div>
<div>
<input type="checkbox" id="syshpcb3" value="Nunney"></input>
<label htmlFor="syshpcb3">Nunney</label>
</div>
<div>
<input type="checkbox" id="syshpcb4" value="Hayesdown"></input>
<label htmlFor="syshpcb4">Hayesdown</label>
</div>
<div>
<input type="checkbox" id="syshpcb5" value="Moorlands"></input>
<label htmlFor="syshpcb5">Moorlands</label>
</div>
<div>
<input type="checkbox" id="syshpcb6" value="Cameley"></input>
<label htmlFor="syshpcb6">Cameley</label>
</div>
<div>
<input type="checkbox" id="syshpcb7" value="St Mary's"></input>
<label htmlFor="syshpcb7">St Mary's</label>
</div>
<div>
<input type="checkbox" id="syshpcb8" value="Other"></input>
<label htmlFor="syshpcb8">Other</label>
</div>
</div>
<input
placeholder="ETA For Fix"
onChange={handleChange}
value={input.eta}
name="eta"
></input>
<button type="Submit" onClick={handleClick}>
Submit
</button>
</form>
</div>
);
}
At The Moment, when you submit the data. It logs the header, content and eta etc correctly
but i want it to essentially create an Array of all the checkboxes that are ticked.
I just don't know where i would even begin..
Will be pushing the data back up to a MongoDB Atlas database once recieved.
Thanks
I have a form with form-groups each containing similar text fields and checkboxes which are sent as arrays when submitting the form as below:
<form method="POST" action="http://localhost/save-form" id="formAddUser">
<div class="form-group">
<input type="text" class="name" name="username[]" />
<input type="text" class="phone" name="phone[]" />
<input type="text" class="country" name="country[]" />
<input type="checkbox" class="isMobile" name="isMobile[]" />
</div>
<div class="form-group">
<input type="text" class="name" name="username[]" />
<input type="text" class="phone" name="phone[]" />
<input type="text" class="country" name="country[]" />
<input type="checkbox" class="isMobile" name="isMobile[]" />
</div>
<div class="form-group">
<input type="text" class="name" name="username[]" />
<input type="text" class="phone" name="phone[]" />
<input type="text" class="country" name="country[]" />
<input type="checkbox" class="isMobile" name="isMobile[]" />
</div>
</form>
After every time someone enters their phone, I want to do a remote validation but I would like to send isMobile field along with the request. Currently I am able to send the phone field for validation but couldn't send the corresponding mobile field along with it in the data attribute. Here is my code
$('#frmAddUser').bootstrapValidator({
fields: {
'phone[]': {
trigger: 'blur',
validators: {
notEmpty: {
message: ' '
},
remote: {
message: 'Phone does not exist',
url: 'http://localhost/verify-phone',
data: function () {
// leaving this empty just sends the phone. How do I send isMobile parameter along with this?
}
},
callback: {
callback: function () {
}
}
}
}
}
})
Edit: The following worked.
remote: {
message: 'Phone does not exist',
url: 'http://localhost/verify-phone',
data: function () {
var isMobile = validator.getFieldElements('isMobile[]').val()
}
},
As suggested by #Sumesh, using validator.getFieldElements('isMobile[]').val() worked
remote: {
message: 'Phone does not exist',
url: 'http://localhost/verify-phone',
data: function () {
var isMobile = validator.getFieldElements('isMobile[]').val()
}
}
Hi I am developing web application in angularjs. I have two forms in one html page. Below is the structure.
<form name="form1">
<input type="text" name="fname" />
<input type="text" name="lname" />
<input type="submit" value="Next" />
</form>
<form name="form2">
<input type="text" name="address" />
<input type="text" name="state" />
<input type="submit" value="Next" />
</form>
On clicking on the next submit button of first form i want to validate first form and i want to scroll to second form and disable the first form.
On clicking on the next submit button of form2 i want to validate second form and i want to submit data to server using $http from both forms(form1 and form2).
May i know is this is possible to achieve this? Also may i know is this is the right way i am following or something else i have to do with above requirement? Any suggestion or help would be greatly appreciated. Thank you.
You can bind all your values to a common object. I am enabling the second form after submitting the first form. In second forms submit function, you just have to loop through the values of common object and append it to formData. If you don't have any reason for having two forms, you can consolidate it into one.
Note: I have not added any form validations. For adding form validations, please refer https://codepen.io/sevilayha/pen/xFcdI
HTML:
<form name="form1" ng-submit="enableForm2()">
<input type="text" name="fname" ng-model="obj.fname" />
<input type="text" name="lname" ng-model="obj.lname" />
<input type="submit" value="Next" />
</form>
<form name="form2" ng-show="enableForm" ng-submit="finalSubmit()">
<input type="text" name="address" ng-model="obj.address" />
<input type="text" name="state" ng-model="obj.state" />
<input type="submit" value="Next" />
</form>
JS:
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope, $http) {
$scope.obj = {};
$scope.enableForm = false;
$scope.enableForm2 = function() {
$scope.enableForm = true;
}
$scope.finalSubmit = function() {
$http({
method: 'POST',
url: YourURL,
withCredentials: true,
headers: {
'Content-Type': undefined
},
data: {},
transformRequest: function(data, headersGetter) {
var formData = new FormData();
angular.forEach($scope.obj, function(value, key) {
formData.append(key, value);
})
return formData;
}
}).then(function(data) {
$scope.enableForm=false;
}).catch(function(data, status) {
})
}
});
You can acheive it vai an Ajax Call not by direct Submit. Moreover Form Submit is not required. (Adding Form tag is optional)
<!DOCTYPE html>
<html>
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/angular_material/1.0.0/angular-material.min.css">
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular-animate.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular-aria.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular-messages.min.js"></script>
<!-- Angular Material Library -->
<script src="http://ajax.googleapis.com/ajax/libs/angular_material/1.0.4/angular-material.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<p>Personal Info</p>
<input type="text" ng-model="form1.fname" name="fname"/>
<input type="text" ng-model="form1.lname" name="lname"/>
<input type="button" ng-click="SubmitForm()" value="Next"/>
<p>Address Info</p>
<input type="text" ng-model="form2.address" name="address"/>
<input type="text" ng-model="form2.state" name="state"/>
<input type="button" ng-click="SubmitForm()" value="Next"/>
</div>
<script>
var app = angular.module('myApp', ['ngMaterial']);
app.controller('myCtrl', function ($scope, $http, $q, HTTPService) {
$scope.form1 = {
fname: '',
lname: ''
};
$scope.form2 = {
address: '',
state: ''
};
$scope.SubmitForm = function () {
let submitFormData = {
form1: $scope.form1,
form2: $scope.form2
};
HTTPService.SubmitData(submitFormData);
}
});
app.factory('HTTPService', function ($http, $q) {
return {
SubmitData: function (formData) {
let apiUrl = 'http://localhost:2000/...';
var req = {
method: 'POST',
url: apiUrl + "SaveData.php",
headers: {
"Content-Type": "application/json",
"Authorization": '',
"Access-Control-Allow-Origin": "*"
},
data: formData
};
var result = $http(req)
.then(function(response) {
return angular.fromJson(response.data);
}, function(response) {
return null;
});
return result;
},
};
});
</script>
</body>
</html>
Using $scope also you will get values of fields which are not in same form.
HTML Code
<div ng-app="App" ng-controller="Ctrl">
<form name="myForm">
<!-- first nested form -->
<div ng-form="form1">
<label><p>Personal Info</p></label>
<input type="text" name="fname" ng-model="myForm.fname"/>
<input type="text" name="lname" ng-model="myForm.lname"/>
</div>
<!-- second nested form -->
<div ng-form="form2">
<label><p>Address Info</p></label>
<input type="text" name="address" ng-model="myForm.address"/>
<input type="text" name="state" ng-model="myForm.state"/>
</div>
<!-- etc. -->
<input type="submit" ng-click="SubmitForm()" value="Next"/>
</form>
</div>
JS/Controller code
var app = angular.module('App');
app.controller('Ctrl', function ($scope) {
$scope.SubmitForm = function () {
var SubmitForm = $scope.myForm;
console.log(SubmitForm);
}
});
You can do someting like below
<form name="form1" ng-submit="moveNext(user)">
<input type="text" ng-model="user.fname" name="fname" required/>
<input type="text" ng-model="user.fname" name="lname" required/>
<input type="submit" value="Next"/>
</form>
<form name="form2" ng-submit="submit(addressData)">
<input type="text" ng-model="addressData.address" name="address"/>
<input type="text" ng-model="addressData.state" name="state"/>
<input type="submit" value="Next"/>
</form>
and in Controller
$scope.userDetails = {};
$scope.addressDetails = {};
$scope.moveNext = function(userData){
$scope.userDetails = userData //Save user Data here and implement logic to scroll to next form and validation
}
$scope.submit = function(addressData){
$scope.addressDetails = addressData;
// and validate the form and Submit data to server here as per your requirement
}
$(document).ready(function () {
jQuery.validator.addMethod("insz", function (value, element) {
var insz = $('#txtINSZ').val()
var controle = parseInt(insz.substring(13, 15))
var getal = insz.substring(0, 2) + insz.substring(3, 5) + insz.substring(6, 8) + insz.substring(9, 12)
var rest = parseInt(getal) % 97
alert("we doin' this mun")
return 97 - rest == controle;
}, "* Amount must be greater than zero");
$('#form1').validate({
rules: {
txtINSZ: {
required: $('#cbInsz').prop('checked') == false,
insz: function () {
$('#cbInsz').prop('checked') == true;
}
}
},
showErrors: function (errorMap, errorList) {
this.defaultShowErrors();// to display the default error placement
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/jquery.validation/1.16.0/jquery.validate.js"></script>
<form method="post" action="#" id="form1" a="" novalidate="novalidate">
<div id="container">
<div class="container-fluid">
<div class="col-xs-12">
<div class="form-horizontal col-xs-4" id="divDimLeft">
<span id="lblTitleAlgemeen">Algemen Informatie</span>
<div class="checkbox" style="margin-left:20px;">
<span id="lblCheck">
<input type="checkbox" id="cbInsz" checked="">
INSZ nummer werknemer gekend?
</span>
</div>
<div class="form-group" id="divINSZ">
<span id="lblINSZ" class="required" for="txtINSZ" aria-required="true">INSZ-nummer gekend?</span>
<input name="ctl00$ContentPlaceHolder1$txtINSZ" type="text" maxlength="15" id="txtINSZ" class="form-control required form valid" oninput="autoInvullen()" aria-required="true" placeholder="__.__.__-___.__" aria-invalid="false" required=""><label id="txtINSZ-error" class="error" for="txtINSZ" style="display: none;"></label>
</div>
<div class="form-group">
<span id="lblNaam" class="required" for="txtNaam" aria-required="true">Naam</span>
<input name="ctl00$ContentPlaceHolder1$txtNaam" type="text" maxlength="40" id="txtNaam" class="form-control form requiredField error" aria-required="true" aria-invalid="true"><label id="txtNaam-error" class="error" for="txtNaam">Dit veld is verplicht.</label>
</div>
<div id="divButton" class="text-right" style="width: 87.5%">
<input type="submit" name="ctl00$ContentPlaceHolder1$btnSubmit" value="Volgende" id="btnSubmit" class="btn btn-primary col-xs-2" style="float: none; min-width:200px;">
</div>
</div>
</div>
</div>
</div>
</form>
I wanted to make a custom validator but for some reason it's not working at all. The required does work so there is no issue with finding the elements in my page. So is there someone who has any idea why it is not working?
Thans in advance, under here you find the code i'm using including the method I wrote and the start of the validate method.
You can't just insert a comparison operator all by itself as the parameter; you need a function that returns the value of this parameter, in this case a boolean from the comparison operator...
$('#form1').validate({
rules: {
txtINSZ: {
required: function() {
return $('#cbInsz').prop('checked') == false;
},
insz: function() {
return $('#cbInsz').prop('checked') == false;
}
....
Solved it, I just putted the rules out of the rules section. After the validation code I putted this:
$('#txtINSZ').rules("add", {
required:true,
insz:true
})
Works perfectly.
I also faced the same situation, but in my case below two steps worked.
use data-rule-insz="true" attribute on your HTML input element for which you want custom validation.
also add a name attribute as mentioned in the below example:-
<input id="customer" name="customer" data-rule-insz="true" required type="text" class="typeahead form-control" />
I have successfully been able to use the code in
jsfiddle.net/y3qayufu/2/ to validate a group of fields but how can I display the error message in a specific location. I would like the error message to appear only once after the submit button has been pressed, preferably above the group, but possibly below.
Instead of this:
I would like this:
Thanks
Use jQuery validation errorPlacement function provided:
JsFiddle updated
$("#findproject_form").validate({
rules: {
....
},
errorPlacement: function(error, element) {
$('label.error').remove();
error.insertAfter("#submit_btn");
}
});
HTML:
<div class="searchbg" id="submit_btn" style="margin-right:0px;">
<input class="bgbttn" type="submit" name="submit" value="" />
</div>
Hi here is a fixed fiddle http://jsfiddle.net/bayahiassem/sdx4ru4s/2/
If you can't open it, here the updated code:
html Only added an id to the h3
<form id="findproject_form" method="post" action="{$BASE_URL}findproject">
<div class="bgtrans">
<h3 id="header">Search By</h3>
<div class="div_bg1">
<div class="searchbg">
<div class="seachbginputbg">
<input class="seachbginput validategroup" type="text" placeholder="Profession" id="Profession" name="Profession" value="" />
</div>
</div>
<div class="searchbg">
<div class="seachbginputbg">
<input class="seachbginput validategroup" type="text" placeholder="Location" id="Location1" name="Location1" value="" />
</div>
</div>
<div class="searchbg" style="margin-right:0px;">
<div class="seachbginputbg">
<input class="seachbginput validategroup" type="text" placeholder="Company" id="Company" name="Company" value="" />
</div>
</div>
<div class="clear"></div>
</div>
<div class="div_bg2">
<div class="searchbg">
<div class="seachbginputbg">
<input class="seachbginput validategroup" type="text" placeholder="Name" id="Name" name="Name" value="" />
</div>
</div>
<div class="searchbg">
<div class="seachbginputbg">
<input class="seachbginput validategroup" type="text" placeholder="Key Words" id="KeyWord" name="KeyWord" value="" />
</div>
</div>
<div class="searchbg" style="margin-right:0px;">
<input class="bgbttn" type="submit" name="submit" value="" />
</div>
<div class="clear"></div>
</div>
</div>
</form>
JS using errorPlacement :
$(document).ready(function () {
jQuery.validator.setDefaults({
debug: true,
success: "valid"
});
$("#findproject_form").validate({
rules: {
Profession: {
require_from_group: [1, ".validategroup"]
},
Location1: {
require_from_group: [1, ".validategroup"]
},
Company: {
require_from_group: [1, ".validategroup"]
},
Name: {
require_from_group: [1, ".validategroup"]
},
KeyWord: {
require_from_group: [1, ".validategroup"]
}
},
errorPlacement: function(error, element) {
console.log(error[0].innerText);
if(error[0].innerText == 'Please fill at least 1 of these fields.' && !errorshowed) {
error.insertAfter("#header");
errorshowed = true;
}
}
});
var errorshowed = false;
$.validator.addMethod("require_from_group", function (value, element, options) {
var $fields = $(options[1], element.form),
$fieldsFirst = $fields.eq(0),
validator = $fieldsFirst.data("valid_req_grp") ? $fieldsFirst.data("valid_req_grp") : $.extend({}, this),
isValid = $fields.filter(function () {
return validator.elementValue(this);
}).length >= options[0];
// Store the cloned validator for future validation
$fieldsFirst.data("valid_req_grp", validator);
// If element isn't being validated, run each require_from_group field's validation rules
if (!$(element).data("being_validated")) {
$fields.data("being_validated", true);
$fields.each(function () {
validator.element(this);
});
$fields.data("being_validated", false);
}
return isValid;
}, $.validator.format("Please fill at least {0} of these fields."));
});
Try this on submit u can put in function definition
var valid=0;
$(this).find('input[type=text], select').each(function(){
if($(this).val() != "") valid+=1;
});
if(valid==0)
{
$('#myDiv').html("please fil atleast one of these");
}