Form Validation in ASP .Net MVC with Angular JS - angularjs

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.

Related

select option with Angular and .net core

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.

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 };
}

Angularjs - dropdown not binding correctly AND not showing initial value

I am attempting to get data via a call to a WebApi within AngularJS. I have verified the service works and I am getting the correct data.
The problem(s) are that the selected item is not appearing AND the binding to the model for the result does not appear to be working.
I am a relative newbie in terms of AngularJS. Can somebody please tell me what I am doing wrong and how to correct the issues?
Thanks in advance!
Here is the angular code:
var app = angular.module("GreatWestSoftware", [])
app.controller("ContactMeByController",
function ($scope, $http ,$window) {
function GetContactByMethods($http) {
//$scope.Message = 'NULL';
//$scope.employees = {};
$http.get('http://localhost:53350/api/ContactBy').then(function (response) {
$scope.ContactByMethods = response.data;
$scope.Message = 'OK';
$scope.gotdata = true;
},
function (err) {
$scope.Message = 'Call failed' + err.status + ' ' + err.statusText;
$scope.ContactByMethods = {};
$scope.gotdata = false;
}
);
//window.setTimeout(function () {
// $scope.gotdata = true;
//}, 1000);
};
function ShowAlert(msg)
{
$window.alert(msg);
}
}
);
Here is the model from MVC:
public class SurveyAnswersHeaderViewModel
{
public int ProductID { get; set; }
[Required]
[Display(Name = "Name:")]
public string Name { get; set; }
[EmailAddress]
[Display(Name = "Your Email Address:")]
public string Email { get; set; }
[Phone]
[Display(Name = "Phone Number:")]
[DataType(DataType.PhoneNumber,ErrorMessage ="Invalid Phone Number")]
public string Phone { get; set; }
[Required]
[Display(Description ="How should you be contacted",Name ="Contact Me By:",Prompt ="Select contact method")]
public int ContactBy { get; set; }
}
Here is the page I am attempting to load:
#model GreatWestSoftware.Models.SurveyAnswersHeaderViewModel
#{
Layout = "~/Views/Shared/_Layout.cshtml";
ViewBag.Title = "Great West Software Site Survey";
}
#using (Html.BeginForm("Create", "SurveyAnswersHeader", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>#ViewBag.SurveyName</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.HiddenFor(m => m.ProductID)
</div>
<div class="form-group">
#Html.LabelFor(model => model.Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Name, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Email, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Email, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Email, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Phone, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Phone, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Phone, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div ng-app="GreatWestSoftware" ng-controller="ContactMeByController" ng-show="DisplayContactBy">
#Html.LabelFor(model => model.ContactBy, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10" >
<select id="ContactByDropdown" ng-model="ContactBy" class="form-inline">
<option ng-repeat="ContactByoption in ContactByMethods" ng-selected="{{ContactByoption.IsSelected==true}}" value="{{ContactByoption.ContactByID}}">{{ContactByoption.ContactMeBy}}</option>
</select>
#*#Html.EditorFor(model => model.ContactBy, new { htmlAttributes = new { #class = "form-control" } })*#
#Html.ValidationMessageFor(model => model.ContactBy, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div>
<h4 class="text-danger">#ViewBag.ErrorMessages</h4>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Start Survey" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Skip", "Index","Home")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
<script src="~/Scripts/GreatWestSoftware.js"></script>
}
I do get the values of the dropdown. But oddly, in the generated code there is a . I'm guessing that this is showing up as the blank entry in the list. The dropdown is also not showing the selected initial value, even though the html seems correct.
The second problem is that on the submittal of the form, the selected value is not being bound to the MVC model.
Here is what appears in the dropdown. The correct data...
Here is the generated html code
The dropdown is not showing the inital value because the value is being initialiazed after the select is created. To fix this you need to load the values on the resolve of your route.
Example:
$routeProvider
.when("/state-name", {
templateUrl: "your-template.html",
controller: "ContactMeByController",
resolve: {
contactByMethodsPromise: function($http){
return $http.get('http://localhost:53350/api/ContactBy');
}
}
})
And in your controller:
app.controller("ContactMeByController",
function ($scope, $http , $window, contactByMethodsPromise) {
$scope.ContactByMethods = contactByMethodsPromise;
}
This should fix the select initial value.
About it not binding, I'm not sure Angular binds it to the MVC Model. It is binding to the variable $scope.ContactBy, which you can then submit to your API.
Also, you should consider using only Angular to render your pages, it's not necessary and will probably cause strange behaviours mixing it with ASP.NET, as you can see here.

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.

Resources