AngularJS object is not properly converted into a ViewModel .NET - c#

I have an AngularJS directive which returns me an array with some values, like this below:
The AngularJS code I'm using to generate this object like above is:
//--------------------------
// service...
service.getSelectedOptions = function() {
var options = [];
for (var I = 0; I < service.optionList.length; ++I) {
var availableOption = service.optionList[I];
if (availableOption.selecionado !== '') {
options.push(availableOption);
}
}
return opcoes;
};
//--------------------------
// controller...
var options = [];
var list = OptionsService.getSelectedOptions();
for (var I = 0; I < list.length; ++I) {
var option = list[I];
options.push({ Handle: option.Handle, Selecionado: option.Selecionado });
}
console.log(options);
// Sending the values to backend...
doPost('..../SaveOptions', { options: options }, function (result) { });
Ok, I created a ViewModel class to receive those objects into my controller.
public class OptionsViewModel {
public int Handle { get; set; }
public string Selecionado { get; set; }
}
My controller is declared like this below:
public JsonResult SaveOptions(OptionsViewModel[] options) {
//...
}
The problem is: if I chose 4 options, the array in the backend has 4 options, but the values are not binded to the objects.
Why that? Anyone knows why? Thanks!!

The solution was modify two parameters in the AJAX call:
Set contentType: "application/json";
Use JSON.stringify(parameters) to the parameters.
Thanks!

Related

asp.net core 2.0 bind model with decimal value

I've been looking for a solution to this case for hours, and I did not find anything that worked out for me.
Here we use the comma for decimal separator, and when I send a value like "15,50", in my controller I get the value of the model as "1550", and it only makes sense if I send "15.50".
I covered the following topics, and nothing worked.
Set CultureInfo in Asp.net Core to have a . as CurrencyDecimalSeparator instead of ,
Aspnet Core Decimal binding not working on non English Culture
I am sending the form with ajax, using the $form.serializeArray() as below:
function getFormData(xform) {
var $form = $('#' + xform);
var unindexed_array = $form.serializeArray();
var indexed_array = {};
$.map(unindexed_array, function (n, i) {
indexed_array[n['name']] = n['value'];
});
return indexed_array;
}
send:
function PostFormAjax(controller, metodo, params, redir, divacao, reloadgrid) {
if (params != null) {
var formData = new FormData();
var json = $.parseJSON(JSON.stringify(params));
$(json).each(function (i, val) {
$.each(val, function (k, v) {
console.log(k + " : " + v);
formData.append(k, v);
});
});
}
$.ajax({
url: '/' + controller + '/' + metodo,
data: JSON.stringify(params),
contentType: 'application/json',
type: 'POST',
success: function (data) {
AjaxFim(metodo, data, redir, divacao, reloadgrid);
}
});
}
My controller:
[HttpPost]
public IActionResult GravaProduto([FromBody] Produtos produto)
{
if (ModelState.IsValid)
{
//produto.Valorcusto is 1550 and not 15,50 as it was posted
//produto.Valorvenda is 1550 and not 15,50 as it was posted
}
}
My Model.cs
public partial class Produtos
{
public int Cod { get; set; }
public string Descricao { get; set; }
public decimal Valorcusto { get; set; }
public decimal Valorvenda { get; set; }
}
I tried to make a replace in formData.append(k, v.replace(',', '.')); and also does not work, I also would not know which field is a decimal.
What do I have to do? because I'm lost, what should have been simpler became more complicated.
What I did to keep working until I found a solution was:
Wear a mask according to my regional setting:
$('.stValor').mask("#.###.##0,00", { reverse: true });
And before posting the form, I switch to the accepted formatting:
$('#fCadAltProd').validator().on('submit', function (e) {
if (e.isDefaultPrevented()) {
} else {
e.preventDefault();
$('.stValor').mask("#,###,##0.00", { reverse: true });
//Ajax post here
}
});
Here we use the comma for decimal separator, and when I send a value like "15,50", in my controller I get the value of the model as "1550", and it only makes sense if I send "15.50".
Create a custom model binder using the Norwegian culture, because Norway also uses the comma decimal separator. You might also want to specify certain multiple allowed number styles.
Here is one that still needs to have error handling. It gives you the basic idea, though, and you can build on it from here. What I would do it copy most of the logic from the built-in DecimalModelBinder.
using System.Globalization;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
using Microsoft.Extensions.Logging;
namespace AspNetCorePlayground.Models
{
public class MyFirstModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
var valueProviderResult = bindingContext
.ValueProvider
.GetValue(bindingContext.ModelName);
var cultureInfo = new CultureInfo("no"); // Norwegian
decimal.TryParse(
valueProviderResult.FirstValue,
// add more NumberStyles as necessary
NumberStyles.AllowDecimalPoint,
cultureInfo,
out var model);
bindingContext
.ModelState
.SetModelValue(bindingContext.ModelName, valueProviderResult);
bindingContext.Result = ModelBindingResult.Success(model);
return Task.CompletedTask;
}
}
}
Then decorate your class like this:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
namespace AspNetCorePlayground.Models
{
public class MyFirstModelBinderTest
{
[ModelBinder(BinderType = typeof(MyFirstModelBinder))]
public decimal SomeDecimal { get; set; }
}
}
I tested it on a controller:
[HttpGet("test")]
public IActionResult TestMyFirstModelBinder(MyFirstModelBinderTest model)
{
return Json(model);
}
This is the result:
Use this plugin jquery.serializeToJSON
and change your getFormData() function to
function getFormData(xform) {
var $form = $('#' + xform);
var obj = $form.serializeToJSON({
parseFloat: {
condition: ".stValor,.stQnt,.stDesconto",
nanToZero: true,
getInputValue: function (i) {
return i.val().split(".").join("").replace(",", ".");
}
}
});
return obj;
}
parseFloat.getInputValue: function(){}, By default, returns the input value without commas, not an error occurs in conversion. if your location uses comma for decimal separation, for example in German or Brazil, you can change to
function(i){
return i.val().split(".").join("").replace(",", ".");
}
This will do all the work for you.

Typewriter in VS2017 - TypeScript dependency loading with RequireJs uses Knockout?

So currently am working on streamlining my front end development with TypeScript and typewriter plug-in for VS.
What I'm currently having issues with is handling my module loading in the browser using RequireJS. I have followed several tuts online and read through the documentations of each of the technologies used even read tons of SO material as well. I'm thinking this is like complex arithmetic where all the sudden it'll click and be a piece of cake but right now all the moving pieces have my mind in a state of spaghetti. I could really use some help here.
I'm going to use a complex class structure example because I believe the issue lies within missing imports and exports / namespace and module declarations however - I don't know for sure because I just can't wrap my head around everything going on here.. yet. I will do my best to provide comprehensive code details using actual app code and structure.
C# Class:
public class SnakeViewModel
{
// Project
public ProjectViewModel Project { get; set; }
public long ProjectId { get; set; }
// Workflow
public Workflow Workflow { get; set; }
public string EntityName { get; set; }
public List<Workflow> Workflows { get; set; }
// Workflow Phases
public List<WorkflowPhase> WorkflowPhases { get; set; }
//Contractors - Name and ID
public List<ContractorDetails> ContractorDetails { get; set; }
...
......
}
TypeWriter Template:
${
using Typewriter.Extensions.Types;
Template(Settings settings)
{
settings.IncludeAllProjects();
settings.OutputExtension = ".ts";
}
string KnockoutType(Property p) {
if (p.Type.IsEnumerable) {
return p.Type.Name.TrimEnd('[',']');
}
return p.Type;
}
string KnockoutValue(Property property) {
var type = KnockoutType(property);
if (IsEnumerableViewModel(property)) {
return $"ko.observableArray<Knockout{type}>([])";
} else if (property.Type.IsEnumerable) {
return $"ko.observableArray<{type}>([])";
}
return $"ko.observable<{type}>()";
}
bool IsEnumerableViewModel(Property p) {
string type = KnockoutType(p);
return p.Type.IsEnumerable && type.EndsWith("ViewModel");
}
}
namespace Sidewinder {
$Classes(RIOT.Mvc4.ViewModels.*)[
export interface $Name {
$Properties[
$name: $Type;]
}
export class Knockout$Name {
$Properties[
public $name = $KnockoutValue;]
constructor(model: $Name) {
this.map(model);
}
public map(model: $Name) {
$Properties(x => !IsEnumerableViewModel(x))[
this.$name(model.$name);]
$Properties(x => IsEnumerableViewModel(x))[
this.$name(model.$name.map(this.map$Name));]
}
$Properties(x => IsEnumerableViewModel(x))[
public map$Name(model: $KnockoutType) {
return new Knockout$KnockoutType(model);
}]
public getModel() {
return {
$Properties(x => !IsEnumerableViewModel(x))[
$name: this.$name(),]
$Properties(x => IsEnumerableViewModel(x))[
$name: this.$name().map(x => x.getModel())][,]
}
}
}]
}
TS Output:
namespace Sidewinder {
export interface SnakeViewModel {
project: ProjectViewModel;
projectId: number;
workflow: Workflow;
entityName: string;
workflows: Workflow[];
workflowPhases: WorkflowPhase[];
contractorDetails: ContractorDetails[];
...
......
}
export class KnockoutSnakeViewModel {
public project = ko.observable<ProjectViewModel>();
public projectId = ko.observable<number>();
public workflow = ko.observable<Workflow>();
public entityName = ko.observable<string>();
public workflows = ko.observableArray<Workflow>([]);
public workflowPhases = ko.observableArray<WorkflowPhase>([]);
public contractorDetails = ko.observableArray<ContractorDetails>([]);
...
......
constructor(model: SnakeViewModel) {
this.map(model);
}
public map(model: SnakeViewModel) {
this.project(model.project);
this.projectId(model.projectId);
this.workflow(model.workflow);
this.entityName(model.entityName);
this.workflows(model.workflows);
this.workflowPhases(model.workflowPhases);
this.contractorDetails(model.contractorDetails);
...
......
}
public getModel() {
return {
project: this.project(),
projectId: this.projectId(),
workflow: this.workflow(),
entityName: this.entityName(),
workflows: this.workflows(),
workflowPhases: this.workflowPhases(),
contractorDetails: this.contractorDetails(),
...
......
}
}
}
}
Compiled JS:
var Sidewinder;
(function (Sidewinder) {
var KnockoutSnakeViewModel = (function () {
function KnockoutSnakeViewModel(model) {
this.project = ko.observable();
this.projectId = ko.observable();
this.workflow = ko.observable();
this.entityName = ko.observable();
this.workflows = ko.observableArray([]);
this.workflowPhases = ko.observableArray([]);
this.contractorDetails = ko.observableArray([]);
...
......
this.map(model);
}
KnockoutSnakeViewModel.prototype.map = function (model) {
this.project(model.project);
this.projectId(model.projectId);
this.workflow(model.workflow);
this.entityName(model.entityName);
this.workflows(model.workflows);
this.workflowPhases(model.workflowPhases);
this.contractorDetails(model.contractorDetails);
...
......
};
KnockoutSnakeViewModel.prototype.getModel = function () {
return {
project: this.project(),
projectId: this.projectId(),
workflow: this.workflow(),
entityName: this.entityName(),
workflows: this.workflows(),
workflowPhases: this.workflowPhases(),
contractorDetails: this.contractorDetails(),
...
......
};
};
return KnockoutSnakeViewModel;
}());
Sidewinder.KnockoutSnakeViewModel = KnockoutSnakeViewModel;
})(Sidewinder || (Sidewinder = {}));
//# sourceMappingURL=SnakeViewModel.js.map
Ok, so that shows all my compilations - next i'm going to show some screenshots of settings and current structure and then show RequireJS code.
Screenshot of File Structure..
Screenshot of TS Compiler Settings..
So now require stuff - it's very rudimentary currently.
Config file:
declare var require: any;
require.config({
baseUrl: "/Scripts"
});
Global Include:
#Scripts.Render("~/bundles/ScriptRequire")
<script src="~/Scripts/app/require-config.js"></script>
Snake.cshtml:
#section scripts{
<script>
require(["App/views/project/snake"]);
</script>
}
Snake.ts:
namespace Sidewinder {
export class ViewModel extends KnockoutSnakeViewModel {
constructor(model: SnakeViewModel) {
super(model);
}
getViewModel() {
}
}
$(function () {
let initModel = {
projId: $("#projId").val(),
wfId: $("#wfId").val()
}
$.post("/ProjectApi/ProjectSnakeView",
initModel,
data => {
if (data != null) {
console.log(data);
var model = new ViewModel(data);
ko.applyBindings(model);
}
});
});
}
Snake.js:
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b;
}) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype =
b.prototype, new __());
};
})();
var Sidewinder;
(function (Sidewinder) {
var ViewModel = (function (_super) {
__extends(ViewModel, _super);
function ViewModel(model) {
return _super.call(this, model) || this;
}
ViewModel.prototype.getViewModel = function () {
};
return ViewModel;
}(Sidewinder.KnockoutSnakeViewModel));
Sidewinder.ViewModel = ViewModel;
$(function () {
var initModel = {
projId: $("#projId").val(),
wfId: $("#wfId").val()
};
$.post("/ProjectApi/ProjectSnakeView", initModel, function (data) {
if (data != null) {
console.log(data);
var model = new ViewModel(data);
ko.applyBindings(model);
}
});
});
})(Sidewinder || (Sidewinder = {}));
//# sourceMappingURL=snake.js.map
Alright.. so that should be all the code. The html itself is all KO bound and I'm simply trying to get it to wire up bindings and display returned data at the moment. I'm getting dependency errors obviously and I don't understand the namespace/module/ having to reference everything even though it builds without issues and the compiler doesn't complain.. ugh.
The only thing that RequireJS is injecting into the page is the Snake.Js file when it obviously should be injecting all required subclasses of the viewmodel itself.
This front-end stuff has gotten a bit complex these days.
I'm sure I've left stuff out and not followed a specific rule to a tee so please inform me of any specific issues with this post before raising a flag - more than willing to answer further questions and learn more.

WebApi2 how to pass Json with an array

I have the following Json with array that I am sending it from AngularJS
{id_fleet: 4177, id_fleetfeature: Array[2]}
var dataFeatures = {
id_fleet: $scope.id,
id_fleetfeature: $scope.selectedFeatures
}
$http.put(myUrl + "Fleets/Insert", JSON.stringify(dataFeatures)).then(function () {
Materialize.toast('Features insertadas correctamente', 3000);
$scope.refreshData();
});
Web API Model
public class modelFleetFeatures {
public int id_fleet { get; set; }
public int[] id_fleetfeature { get; set; }
}
Web API Function
[HttpPut]
[Route("api/Fleets/FleetFeature/Update")]
public HttpResponseMessage updateFleetFeature(List<modelFleetFeatures> data)
{
var cnt = 0;
foreach (var item in data)
{
db.sp_Fleet_FleetFeaturesDelete(item.id_fleet);
db.SaveChanges();
}
foreach (var item in data)
{
db.sp_Fleet_FleetFeaturesInsert(item.id_fleet, item.id_fleetfeature[cnt]);
db.SaveChanges();
cnt +=1;
}
return new HttpResponseMessage { StatusCode = HttpStatusCode.OK };
}
In the Web API the value of data always gets null
You are sending single object in JSON, so why expecting list of object in API action?
Just expect single object in api Action , you will get that object model in call like :
public HttpResponseMessage updateFleetFeature(modelFleetFeatures data)
{
//do stuff
}
And no need to stringify json object in put request.
$http.put(myUrl + "Fleets/Insert", dataFeatures).then(function () {
Materialize.toast('Features insertadas correctamente', 3000);
$scope.refreshData();
});

Ho to pass a Model Object or a Viewbag to Javascript?

I am using asp.net mvc4 with C#. I get the details from Getdeatils() method of student class. This method return an array. Getdetails method also have same fields like studentBO. In the controller I have a method like follows
public ActionResult Index()
{
List<studentBO> list = new List<studentBO>();
Student.GetDetails[] dt = Student.Getdeatils();
for (int i = 0; i < dt.Length; i++)
{
studentBO.name= dt[i].name;
studentBO.studentno= dt[i].studentno;
studentBO.address= dt[i].address;
list1.Add(studentBO);
}
ViewBag.Registrationlist = list1;
return View(list1);
}
studentBO object have 3 fields
public class studentBO
{
public long studentno{ get; set; }
public string name{ get; set; }
public string address{ get; set; }
}
How can I get viewbag or model in my Jquery `$(document).ready(function () {}` function. I want to get every students name. So I have to use foreach loop as well.
You can serialise your item in the ViewBag and write it to the view, so that the Javascript code will be able to read it:
$(document).ready(function() {
var registrationList = #(Html.Raw(new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(ViewBag.Registrationlist)));
for (var i = 0; i < registrationList.length; i++) {
var studentno = registrationList[i].studentno;
var name= registrationList[i].name;
var address= registrationList[i].address;
// write some more code to make use of the values
}
});
Use WebAPI to create a service that returns your objects. Then you can use an ajax-call in your Javascript code to fetch the objects.
WebAPI:
public class StudentsController : ApiController
{
IEnumerable<Student.GetDetails> GetDetails()
{
List<studentBO> list = new List<studentBO>();
Student.GetDetails[] dt = Student.Getdeatils();
for (int i = 0; i < dt.Length; i++)
{
studentBO.name= dt[i].name;
studentBO.studentno= dt[i].studentno;
studentBO.address= dt[i].address;
list1.Add(studentBO);
}
return list1;
}
}
Javascript:
$(document).ready(function () {
// Send an AJAX request
$.getJSON("api/students")
.done(function (data) {
// On success, 'data' contains a list of students.
$.each(data, function (key, item) {
//Do something with the student object
});
});
});

Deserialize javascript objects to generic list in c# handler

Im creating some javascript items in a loop
var licenseList = {};
$($licenses).each(function (index) {
var license = {};
var editedValues = {};
license.PRODUCT_KEY = $(this).parent('div.licensewrapper').data('productkey');
$(this).find('input:text').each(function (i, val) {
if ($(val).attr('data-default-value') != $(val).val() && $(val).val() > 0 && $(val).data('isValid') != false) {
var pogKey = $(val).data('product_option_group_key');
var editedValue = $(val).val();
editedValues[pogKey] = editedValue;
license.editedValues = editedValues;
}
});
//licenseList[index] = license;
//liceneList.push(license); //if array...
});
I've commented out my current solutions. But i dont think any of the two are equal to a generic list when derelializing them in c#. Whats the corrent way to do it in this case? Thanks
create your array
var licenseList = [];
for each of your licenses...
var license = {
prop1: 'p1',
prop2: 'p2'
};
licenseList.push(license);
format and serialize JSON data to be sent over to webmethod
data = {
LicenseList: licenseList
};
$.ajax({
...
data: JSON.stringify(data)
...
});
in your webmethod your method parameter must match
[WebMethod]
public static string GetLicenses(List<License> LicenseList)
{
foreach(var license in LicenseList)
{
// do whatever
}
}
sample license class. Your properties need to match with your objects in your javascript
public class License
{
public string Prop1 {get; set;}
public string Prop2 {get; set;}
}
Hope this helps.
function sendToServer(licenseList)
{
var url = "controller.ashx";
var data = {};
data.SerializedObj = JSON.stringify(licenseList);
$.post(url, data, function(response){
if(response.length > 0)
{
alert(response);
}
});
}
//controller.ashx :
public void ProcessRequest (HttpContext context) {
//...
string serializedObj = context.Request.Form["SerializedObj"] ?? "";
JavaScriptSerializer js = new JavaScriptSerializer();
List<license> collection = js.Deserialize<List<license>>(serializedObj);
//...
public class license
{
public string Propertie1 {get;set;}
public string Propertie2 {get;set;}
}
Javascript object must have the same properties:
var license = {Propertie1 : 'value1', Propertie2 : 'value2'};

Categories

Resources