select option with Angular and .net core - angularjs

I have angular controller for get and post some data.
I made two controller to work correctly and now when I made 3rd one with mixing two previous controllers get and post doesn't work. Could you help to find a problem ?
Here is a code.
sparePartController.js
//sparePartController.js
(function () {
"use strict";
angular.module("app")
.controller("sparePartController", sparePartController);
function sparePartController($http)
{
var vm = this;
vm.spareParts = [];
vm.newSparePart = {};
vm.errorMessage = "";
vm.isBusy = true;
$http.get("/spares/getAll")
.then(function (response) {
//success
angular.copy(response.data, vm.spareParts);
}, function (error) {
vm.errorMessage = error;
}).finally(function () {
vm.isBusy = false;
});
vm.addSparePart = function () {
vm.isBusy = true;
vm.errorMessage = "";
$http.post("/spares", vm.newSparePart)
.then(function (response) {
console.log("test");
vm.spareParts.push(response.data);
vm.newSparePart = {};
}, function () {
console.log = "failed to save new spare";
vm.errorMessage = "failed to save new spare";
}).finally(function () {
vm.isBusy = false;
});
};
}
})();
Index.cshtml to show spare parts and add new one
#model IEnumerable<RnD.Models.ViewModels.SparePartViewModel>
#{
ViewBag.Title = "Spare Parts List";
}
#section scripts{
<script src="~/lib/angular/angular.js"></script>
<script src="~/js/app.js"></script>
<script src="~/js/sparePartController.js"></script>
<script src="~/js/spareTypeController.js"></script>
<script src="~/js/machineController.js"></script>
}
<div class="row" ng-app="app" ng-controller="sparePartController as vm">
<!-- Start Modal-->
<!-- Button trigger modal -->
<button type="button" class="btn btn-primary btn-lg" data-toggle="modal" data-target="#myModal">
Create New Spare Part
</button>
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="myModalLabel">Modal title</h4>
</div>
<div class="modal-body">
<form novalidate name="newSpareForm" ng-submit="vm.addSparePart()">
<div class="form-group">
<label for="InternalCode">Internal Code</label>
<input class="form-control" type="text" placeholder="Internal Code" id="InternalCode" ng-model="vm.newSparePart.internalCode" required min="3" />
</div>
<div class="form-group" ng-controller="machineController as machineVM">
<label>Machine Type</label>
<select class="form-control" ng-model="machineVM.machineType" ng-options="machine.name for machine in machineVM.machines"></select>
</div>
<div class="form-group" ng-controller="spareTypeController as spareVM">
<label>Spare Type</label>
<select class="form-control" ng-model="spareVM.id">
<option ng-repeat="spare in spareVM.spares" value="{{spare.id}}">{{spare.name}}</option>
</select>
</div>
<div class="form-group">
<input type="submit" value="Add" class="btn btn-success" />
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
<!-- End Modal-->
</div>
<hr />
<div class="panel panel-default" ng-repeat="spare in vm.spareParts">
<div class="panel-heading">
{{spare.internalCode}} //it was vm.internalCode
</div>
<div class="panel-body">
</div>
<div class="panel-footer">
</div>
</div>
</div>
P.S. To add, when I want to post I have problem to catch value from select. Internal code is recognized from angular controller but machinetype it is not recognized that filed always is null.
here is modelview class
public class SparePartViewModel
{
[Required]
[StringLength(100)]
public string InternalCode { get; set; }
[StringLength(4096)]
public string Description { get; set; }
[StringLength(255)]
public string NameOnFolder { get; set; }
public decimal? Enter { get; set; }
public decimal? Exit { get; set; }
public decimal? Thickness { get; set; }
public string Band { get; set; }
public string Color { get; set; }
public bool Elastic { get; set; }
[Required]
public MachineType MachineType { get; set; }
[Required]
public virtual SpareType SpareType { get; set; }
}
I even try in index.cshtml to put this code <select class="form-control" ng-model="vm.newSparePart.machineType" ng-options="machine.name for machine in machineVM.machines"></select> but in this case when I call [From Body] my viewModel is null
Here is my SparePartsController.cs
[Route("/spares")]
[Authorize]
public class SparePartsController : Controller
{
private ILogger<SparePartsController> _logger;
private ISparePartRepository _repository;
public SparePartsController(ISparePartRepository repository, ILogger<SparePartsController> logger)
{
_logger = logger;
_repository = repository;
}
[HttpGet("")]
public IActionResult Index()
{
return View();
}
[HttpGet("getAll")]
public IActionResult Get()
{
try
{
var results = _repository.GetAllSpares();
return Ok(Mapper.Map<IEnumerable<SparePartViewModel>>(results));
}
catch (Exception ex)
{
_logger.LogError($"Failed to get all Spares : {ex}");
return BadRequest("Error Occurred");
}
}
[HttpPost("")]
public async Task<IActionResult> Post([FromBody]SparePartViewModel viewModel)
{
if (ModelState.IsValid)
{
var newSpare = Mapper.Map<SparePart>(viewModel);
_repository.AddSpare(newSpare);
if (await _repository.SaveChangesAsync())
{
return Created($"spare/{newSpare.InternalCode}", Mapper.Map<SparePartViewModel>(newSpare));
}
}
return BadRequest("Failed to save spare.");
}
}

I see a few things off here. 1. I don't think /spares is the full URL to the add method. 2. Even if it were, you still need to send it a correct signature - i.e. the items within the object you send need to match with items in the add spares method signature. 3. I don't see where your newSparePart object is getting assigned values; it's just an empty object. Share the method signature for your add spare method so we can verify that the serialized object. Which brings up 4. You likely need to serialize your object to json: JSON.stringify(vm.newSparePart) when you send it via HTTP post.

Related

Proceed to another view on button click AngularJS

I have a drop down which is displaying data from a Web API. The data is shown below
here's the code for the drop down
<select ng-model="details" ng-options="x.Name for x in customers"></select>
then I have a text box and a button:
<input type="password" ng-model="pin" ng-required="true"/>
<button ng-click="pinForm.$valid && (count = count + 1)" ng-init="count=0">Proceed</button>
Now there are 2 things I want to implement:
with details.PIN I get the PIN of the selected person in the drop down. What I want to do is on button click to check if the pin entered in the text box match to details.PIN; if so, proceed to another view
I have implemented a count on the button. If the count reach to 3 and the pin entered is wrong, I need to show an error message.
The HTML for the only view I have till now
<body ng-app="customerApp">
<div ng-controller="CustomerCtrl" align="center">
<select ng-model="details" ng-options="x.Name for x in customers"></select>
<h1>you selected {{details.Name}}</h1>
<p>his card status is {{details.cardStatus}}</p>
<hr>
<div ng-switch="details.cardStatus">
<div ng-switch-when="0">
<form name="pinForm">
<input type="password" ng-model="pin" ng-required="true"/>
<p><button ng-click="pinForm.$valid && (count = count + 1)" ng-init="count=0">Proceed</button></p>
<p><span>Attempts left: {{3-count}}</span></p>
</form>
</div>
<div ng-switch-when="1">
<p>This card has been reported as stolen and will be retained. If it is yours, please contact your nearest branch</p>
</div>
<div ng-switch-when="2">
<p>This card has been reported as lost and will be retained. If it is yours, please contact your nearest branch</p>
</div>
</div>
</div>
</body>
</html>
Here is the code for the API
namespace test.Controllers
{
[RoutePrefix("Customer")]
public class CustomerController : ApiController
{
[Route("CustomerRecords")]
public List<Customer> Get()
{
return new List<Customer>()
{
new Customer { CID=1, Name="Bruce Wayne", PIN="1234", Bal=1000000, cardStatus= "0" }
,new Customer { CID=2, Name="Steve Rogers", PIN="2246", Bal=900000, cardStatus= "0" }
,new Customer { CID=3, Name="Jon Snow", PIN="2398", Bal=3000, cardStatus= "1" }
,new Customer { CID=4, Name="Rustin Cohle", PIN="7549", Bal=450000, cardStatus= "2" }
//NOTE
//cardStatus '0' :valid
//cardStatus '1' :stolen
//cardStatus '2' :lost
};
}
}
public class Customer
{
public int CID { get; set; }
public string Name { get; set; }
public string PIN { get; set; }
public int Bal { get; set; }
public string cardStatus { get; set; }
}
}
here's the module, the service and the factory method the code for routing the views:
var customerAppModule = angular.module("customerApp", []);
customerAppModule.controller('CustomerCtrl', function ($scope, CustomerService)
{
getCustomerRecords();
function getCustomerRecords() {
CustomerService.getCustomers()
.success(function (data) {
console.log(data);
$scope.customers = data;
})
.error(function (data, status) {
console.error('failure loading the customer record', status, data);
$scope.customers = {};
});
}
});
customerAppModule.factory('CustomerService', ['$http', function ($http) {
var customerService = {};
var urlBase = 'http://localhost:51701/Customer';
customerService.getCustomers = function () {
return $http.get(urlBase + '/CustomerRecords');
};
return customerService;
}]);
var app = angular.module('routeApp', ['ngRoute']);
app.config(function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'Views/Home/index.cshtml',
controller: 'CustomerCtrl'
})
.when('/MainMenu', {
templateUrl: 'Views/Home/MainMenu.cshtml',
controller: 'CustomerCtrl'
})
});
I'm not sure I've written the code for the routing correctly.
What if you change the ng-click logic, to consums a function instead an expression.
Example
HTML
<body ng-controller="MainCtrl as vm">
<select ng-model="vm.details" ng-options="x.Name for x in vm.customers">
<option value="">Select...</option>
</select>
<h1>you selected {{vm.details.Name}}</h1>
<p>his card status is {{vm.details.cardStatus}}</p>
<hr>
<div ng-switch="vm.details.cardStatus">
<div ng-switch-when="0">
<form name="vm.pinForm">
<input type="password" ng-model="vm.pin" ng-required="true"/>
<p><button ng-disabled="vm.count >=3" ng-click="vm.pinFormCheck();" ng-init="vm.count=0">Proceed</button></p>
<p><span>Attempts left: {{3-vm.count}}</span></p>
</form>
</div>
<div ng-switch-when="1">
<p>This card has been reported as stolen and will be retained. If it is yours, please contact your nearest branch</p>
</div>
<div ng-switch-when="2">
<p>This card has been reported as lost and will be retained. If it is yours, please contact your nearest branch</p>
</div>
<div ng-if="vm.failPin">
<p>Invalid Pin</p>
</div>
<div ng-if="vm.count >=3">
<p>Not Enoguh Attempts</p>
</div>
</div>
</body>
CONTROLLER
var vm = this;
vm.customers = [
{CID:1, Name:'Bruce Wayne', PIN: '1234', Bal: 10000, cardStatus: '0'},
{CID:2, Name:'Steve Rogers', PIN: '2246', Bal: 90000, cardStatus: '0'},
{CID:3, Name:'Jon Snow', PIN: '2398', Bal: 30000, cardStatus: '1'},
{CID:4, Name:'Rustin Cohle', PIN: '7549', Bal: 45000, cardStatus: '2'}
];
vm.pinFormCheck = function(){
vm.count++;
if(vm.pinForm.$valid && (vm.details.PIN === vm.pin) && (vm.count <= 2)){
console.log('all good'); //change location.
}else{
vm.failPin = true;
console.log('atemps', vm.count);
}
};
Working Example in this HERE
Hope this example is good enough for your UNIT CASE

the server responded with a status of 500 (Internal Server Error)(asp.net mvc and angular js)

I am Getting null value in action method when i am pass data from angular js to action method. i debug and see it hit to the AddCutomer method but data is null(the server responded with a status of 500 (Internal Server Error). can anyone help me to fix this issue
Admin.js
var app = angular.module("adminmdl", [])
app.controller("admincontroller", function ($scope, AdminService) {
$scope.Action = 'Add';
GetAllCustomer();
function GetAllCustomer() {
var getcust = AdminService.getCustomer();
getcust.then(function (cust) {
$scope.customers = cust.data;
}, function () {
alert('Error');
});
}
$scope.data = {
cus_code: '',
cus_name: ''
}
$scope.savecu = function () {
AdminService.saveCustomerDdetails($scope.cusmodel).then(function (d) {
$scope.msg = "Insert Successfully";
});
}
})
.service('AdminService', function ($http) {
this.getCustomer = function () {
return $http.get('GetCustomer');
}
this.saveCustomerDdetails = function (customer) {
return $http.post('/AddCutomer', customer);
}
})
ASP.NET MVC
[HttpPost]
public JsonResult AddCutomer(Customer customer) {
te.Customers.Add(customer);
te.SaveChanges();
string message = "Success";
return new JsonResult { Data = message, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}
html code
<form class="form-horizontal" method="post" ng-submit="savecu()" name="basic_validate" id="basic_validate" novalidate="novalidate">
<div class="control-group">
<label class="control-label">Customer Code</label>
<div class="controls">
<input type="text" ng-model="cusmodel.Customercode" name="required" id="required" >
</div>
</div>
<div class="control-group">
<label class="control-label">Customer Name</label>
<div class="controls">
<input type="text" ng-model="cusmodel.Customername" name="name" id="name" >
</div>
</div>
<div class="control-group">
<div class="controls">
<input type="submit" value="Save" ng-click="savecu()" class="btn btn-success">
<input type="submit" value="Clear" class="btn btn-success" />
</div>
</div>
<div class="control-group">
<div class="controls">
<p style="color:green">{{msg}}</p>
</div>
</div>
#*<div class="form-actions">
</div>*#
</form>
Ok, so this is your autogenerated class
public partial class Customer
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.??Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Customer()
{
this.projects = new HashSet<project>();
}
public string cus_code { get; set; }
public string cus_name { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.??Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<project> projects { get; set; }
}
The first issue I see is that your client object that you post to the server doesn't match the class definition.
Change the ng-models to cusmodel.cus_code and cusmodel.cus_name
<div class="control-group">
<label class="control-label">Customer Code</label>
<div class="controls">
<input type="text" ng-model="cusmodel.cus_code" name="required" id="required" >
</div>
</div>
<div class="control-group">
<label class="control-label">Customer Name</label>
<div class="controls">
<input type="text" ng-model="cusmodel.cus_name" name="name" id="name" >
</div>
</div>
The names in the scope model need to match the class specification else the json deserializer don't know what to do here.
Try to make a new post when these changes are added and see if the values of the cus_code and cus_name is populated.
If this doesn't work I would use a data transfer object to handle the communication with the client instead. Populating autogenerated classes from EF(or what orm you use) from the client can be a mess.
Add this class:
public class CustomerDTO
{
public string cus_code { get; set; }
public string cus_name { get; set; }
}
And use it in the controller method
[HttpPost]
public JsonResult AddCutomer(CustomerDTO customer) {
var cust = new Customer{ cus_code = customer.cus_code, cus_name = customer.cus_name };
te.Customers.Add(cust);
te.SaveChanges();
string message = "Success";
return new JsonResult { Data = message, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}

Angular JS form validation using ModelState in Web API Core

I am working on a Web Application with client side in AngularJS, TypeScript and HTML, and the server side is a .NET Core Web API.
I want to implement server side validation using ModelState and DTOs. The thing is that I don't want to display all the validation errors at the top of the Form, but I want to display them in-line with the textbox
So first I added the validations to a DTO and then checking in the controller for ModelState.IsValid
public class TestDTO
{
[Required(ErrorMessage = "This field is required")]
public string TestName { get; set; }
}
public class ManyTestDTO
{
[Required(ErrorMessage = "Many Item is required")]
public string ManyItem { get; set; }
}
public class RestaurantDTO
{
public int RestaurantId { get; set; }
[Required(ErrorMessage = "This field is required")]
public string Name { get; set; }
[Required(ErrorMessage = "This field is required"), MaxLength(20), MinLength(1)]
public string Description { get; set; }
[Required(ErrorMessage = "This field is required")]
public string Address { get; set; }
public TestDTO TestModel { get; set; }
public List<ManyTestDTO> TestMany { get; set; }
public RestaurantDTO()
{
}
}
Getting the idea from this link: Link - I have created a directive in my Application to display the validation message in-line, it is working fine the problem is that the HTML I am writing to show the validation message is complex.
The Directive
export class ServerValidationDirective implements ng.IDirective {
constructor() { }
restrict: "A";
require: "ngModel";
link = function (scope, element, attrs, ctrl) {
scope.$watch("controller.modelState", () => {
let modelState = scope.controller.modelState;
console.log(modelState);
if (modelState == null) return;
let state = modelState[attrs.ngServerValidate];
if (state) {
// Server Errors exist for the ngServerValidate
scope.controller.parsedModelState[attrs.ngServerValidate] = state;
} else {
// No Error for the ngServerValidate
if (scope.controller.parsedModelState[attrs.ngServerValidate]) {
scope.controller.parsedModelState[attrs.ngServerValidate] = null;
}
}
});
};
static factory(): ng.IDirectiveFactory {
var directive = () => new ServerValidationDirective();
return directive;
}
}
The Controller:
class CreateRestaurantController {
static $inject = ["$scope"];
restaurantModel: any;
modelState: any;
parsedModelState: any;
testModelState:any;
constructor($scope) {
this.scope = $scope; // create a local copy of the $scope
this.scope.controller = this; //put controller reference in this.scope.controller
this.restaurantModel = {name: "Dawood",testModel: {},testMany: [{ ManyItem: "I have a Value" },{}]};
this.modelState = null;
this.parsedModelState = {};
this.testModelState = JSON
.parse('{"Address":["This field is required"],"Description":["This field is required"],"TestModel.TestName":["This field is required"],"TestMany[1].ManyItem":["Many Item is required"]}');
console.log(this.testModelState);
}
testValidation() {
this.modelState = this.testModelState;
//Normally modelStae will be return from server
// Submit to Server
//this.apiService.post("/api/RestaurantDashboard/GetTestValidation",
// null, this.restaurantModel,
// response => {
// console.log(response);
// },
// response => {
// this.modelState = response.data;
// });
}
}
The HTML for the Form
<div ng-app="validationApp">
<div ng-controller="validationController">
<form name="restaurantForm" class="form">
<div class="form-group" ng-class="{'has-error': controller.parsedModelState.Name != null}">
<label>Restaurant Name</label>
<input type="text" class="form-control" ng-server-validate="Name" ng-model="controller.restaurantModel.name">
<span class="help-block" ng-repeat="errorMessage in controller.parsedModelState.Name"> {{errorMessage}} </span>
</div>
<div class="form-group" ng-class="{'has-error': controller.parsedModelState.Address != null}">
<label>Address</label>
<input type="text" class="form-control" ng-server-validate="Address" ng-model="controller.restaurantModel.address">
<span class="help-block" ng-repeat="errorMessage in controller.parsedModelState.Address"> {{errorMessage}} </span>
</div>
<h3>Nested Object</h3>
<div class="form-group" ng-class="{'has-error': controller.parsedModelState['TestModel.TestName'] != null}">
<label>TestModel.TestName</label>
<input type="text" class="form-control" ng-server-validate="TestModel.TestName" ng-model="controller.restaurantModel.testModel.testName">
<span class="help-block" ng-repeat="errorMessage in controller.parsedModelState['TestModel.TestName']"> {{errorMessage}} </span>
</div>
<h3>Many Array/List</h3>
<ul class="list-unstyled">
<li ng-repeat="item in controller.restaurantModel.testMany">
<div class="form-group" ng-class="{'has-error': controller.parsedModelState['TestMany[' + $index + '].ManyItem'] != null}">
<label>Many Item {{$index}}</label>
<input type="text" class="form-control" ng-server-validate="{{'TestMany[' + $index + '].ManyItem'}}" ng-model="item.ManyItem">
<span class="help-block" ng-repeat="errorMessage in controller.parsedModelState['TestMany[' + $index + '].ManyItem']"> {{errorMessage}} </span>
</div>
</li>
</ul>
<button class="btn btn-primary" ng-click="controller.testValidation()">Click Me to Check</button>
</form>
</div>
</div>
As you can see the HTML structure for the Many Array/List and Nested Object is a bit complex. Is there a better way to do this?
Fiddle: https://jsfiddle.net/mdawood1991/ua9mk7qz/

Angularjs sending null object to asp mvc action on $http get

I'm trying to use Angularjs to send an object to an asp mvc controller on submit, but the value is going as null.
What I'm missing here?
My controller:
public class RelatorioIndiceController : Controller
{
public ActionResult Index()
{
return View();
}
public JsonResult GerarRelatorio(RelatorioFiltroPesquisa filtro)
{
throw new NotImplementedException();
}
}
My parameter class:
public enum TipoRelatorio
{
IndiceCapacidade,
ImpactoMedio,
TempoMedio
}
public class RelatorioFiltroPesquisa
{
public TipoRelatorio TipoRelatorio { get; set; }
public string NomeRelatorio { get; set; }
public string Data { get; set; }
}
And my view:
<div ng-app="mainApp" id="body">
<div ng-controller="myCtrl" id="form">
<div class="radio">
<label>
<input type="radio" ng-model="Filtro.TipoRelatorio" value="0" name="TiposRelatorio" />
Índice Capacidade
</label>
</div>
<div class="radio">
<label>
<input type="radio" ng-model="Filtro.TipoRelatorio" value="1" name="TiposRelatorio" />
Impacto Médio
</label>
</div>
<div class="radio">
<label>
<input type="radio" ng-model="Filtro.TipoRelatorio" value="2" name="TiposRelatorio" />
Tempo Médio
</label>
</div>
<div class="input-group">
<label>Nome Relatório</label>
<input type="text" ng-model="Filtro.NomeRelatorio" class="form-control" />
</div>
<div class="input-group">
<label>Data</label>
<input type="text" ng-model="Filtro.Data" class="form-control" placeholder="__/__/____" />
</div>
<input type="submit" ng-click="Submit()" value="Gerar Relatório" />
</div>
</div>
#section scripts
{
<script src="~/Scripts/angular.min.js"></script>
<script>
angular.module('mainApp', [])
.controller('myCtrl', ['$scope', '$http', function ($scope, $http) {
$scope.Submit = function () {
$http({
method: "GET",
url: "/RelatorioIndice/GerarRelatorio/",
params: { filtro: $scope.Filtro }
})
.success(function (data) {
console.log("Sucesso");
});
}
}]);
</script>
}
I've checked if the object has the same properties names and they are ok, I made of copy and paste them. I've already checked another similar questions here on SO, but they didn't help me on this issue.
It happened the problem was with this code:
$http({
method: "GET",
url: "/RelatorioIndice/GerarRelatorio/",
params: { filtro: $scope.Filtro }
})
.success(function (data) {
console.log("Sucesso");
});
Changing it to this version solved the problem:
$scope.submit = function() {
$http.get("/RelatorioIndice/GerarRelatorio/", $scope.Filtro)
.success("Sucesso");
};
In the controller you need to allow get requests:
public JsonResult GerarRelatorio(FiltroRelatorioPesquisa filtro)
{
...
return Json(result, JsonRequestBehavior.AllowGet);
}
The old code is a working solution, but only with earlier versions of Angular (I'm not sure which we use at my work. There I'm used to that sintax). As for 1.5.8 the new code was what worked.

Form Validation in ASP .Net MVC with Angular JS

I am trying to migrate my demo project to Angular as I am learning the same. But I faced a dilemma as whether to opt for a razor view form validation while adding or rather updating some info on the client side
or to opt for Angular JS ?
So In Angular How would I achieve the same.
Suppose I have a _AddDetails.cshtml partial view :
#model MvcApplication4.Models.Student
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend><strong>Create a record</strong></legend>
<div class="editor-label">
#Html.LabelFor(model => model.LastName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.LastName)
#Html.ValidationMessageFor(model => model.LastName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.FirstName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.FirstName)
#Html.ValidationMessageFor(model => model.FirstName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.UserName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.UserName)
#Html.ValidationMessageFor(model => model.UserName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Password)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Password)
#Html.ValidationMessageFor(model => model.Password)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.DepartmentID)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.DepartmentID)
#Html.ValidationMessageFor(model => model.DepartmentID)
</div>
<p>
<input type="submit" class="createDetails" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
and in MVC I have opted for FluentValidation of the model.
The model looks like :
[FluentValidation.Attributes.Validator(typeof(StudentViewModelValidator))]
public class Student
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int StudentId { get; set; }
public String LastName { get; set; }
public String FirstName { get; set; }
public String UserName { get; set; }
public String Password { get; set; }
[ForeignKey("Department")]
public int DepartmentID { get; set; }
//Department Navigational Property
public Department Department { get; set; }
}
And the validation looks like :
public class StudentViewModelValidator : AbstractValidator<Student>
{
public StudentViewModelValidator()
{
RuleFor(m => m.FirstName)
.NotEmpty().WithMessage("First Name is required.")
.Matches(#"^\D*$").WithMessage("Numbers are not allowed in First Name");
RuleFor(m => m.LastName)
.NotEmpty().WithMessage("Last Name is required.")
.Matches(#"^\D*$").WithMessage("Numbers are not allowed in Last Name");
RuleFor(m => m.UserName)
.NotEmpty().WithMessage("User Name is required.")
.Matches(#"^[a-zA-Z0-9\.\$]*$").WithMessage("Only . and $ are allowed special characters in a user name");
RuleFor(m => m.Password)
.NotEmpty().WithMessage("Password is required.")
.Length(4, 10).WithMessage("Password should be 4 to 10 characters long")
.Matches(#"^(?=(\D*\d){2,})(?=([^a-zA-Z]*[a-zA-Z]))(?=[^\.\$\~\&]*[\.\$\~\&]).*").WithMessage("Password should contain at least 2 digits,a letter and at least a special character in it");
}
But in angular if I re-build my view instead of this razor template how would I achieve these sort of complex regex validations ?
I know I have something like
ng-required
ng-minlength
ng-maxlength
But how would I achieve like the above razor validations?
Use can use ng-pattern for regex
<script>
angular.module('ngPatternExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.regex = '\\d+';
}]);
</script>
<div ng-controller="ExampleController">
<form name="form">
<label for="regex">Set a pattern (regex string): </label>
<input type="text" ng-model="regex" id="regex" />
<br>
<label for="input">This input is restricted by the current pattern: </label>
<input type="text" ng-model="model" id="input" name="input" ng-pattern="regex" /><br>
<hr>
input valid? = <code>{{form.input.$valid}}</code><br>
model = <code>{{model}}</code>
</form>
</div>
Reference :
https://docs.angularjs.org/api/ng/directive/ngPattern
I implemented the validation in my MVC project that uses angular, so I used the ng-pattern, I had a problem trying to include some special chars as valid for the user name: "#", "_" and "-".
The only way I succeed was to add them as separate repeatable chars at the end of my pattern:
ng-pattern="/^[a-zA-Z0-9.]*[#('_')]*[#('-')]*[#('#')]*$/"
I hope this works for you.

Resources