How to pass updated list to controller? - c#

I'm in the middle of developing a Skills feature in my project And I'm trying to figure out how to do the next thing, I will first describe how the system is built so far:
There is a selectsize text window that allows you to select several skills together, after you select a link, it inserts it below the selection window and asks you what level of your chosen skill.
It can be added and deleted, but it slightly complicates me because I can not find a way to transfer all the selected skills and also selected their level to the controller.
I just want to know in Controller what only the selected skills and their level, that's my code so far built:
List type:
public class SkillDetails
{
public uint SkillID { get; set; }
public Levels Level { get; set; }
public SkillDetails(uint id, Levels level) =>
(SkillID, Level) = (id, level);
}
List definition:
public IList<Skill.SkillDetails> Skills { get; set; }
Javascript - On select event:
Skills[0].SkillID is just a test and it didn't work and it crashes the website.
$eventSelect.on("select2:select", function (e)
{
console.log("select: ", e);
var fieldWrapper = $("<div class=\"fieldwrapper\" id=\"field" + e.params.data.id + "\"/>");
var fType = $('<div class="input-group mb-2"><span class="input-group-prepend"><span class="input-group-text">' + e.params.data.text + '</span ></span ><input type="hidden" name="Skills[0].SkillID" value="' + e.params.data.id + '"/><select class="form-control" name="TEST"><option value="0">None</option><option value="1">Know</option><option value="2">Understand</option><option value="3">Master</option></select></div>');
fieldWrapper.append(fType);
$("#buildyourform").append(fieldWrapper);
});
Javascript - On un-select event:
Here whats happen when delete skill selected from selectsize.
$eventSelect.on("select2:unselect", function (e)
{
console.log("unselect: ", e);
$( "#field" + e.params.data.id).remove();
});
HTML User interact with skills:
<div class="input-group mb-2">
<span class="input-group-prepend">
<span class="input-group-text">' + e.params.data.text + '</span ></span >
<input type="hidden" name="Skills[0].SkillID" value="' + e.params.data.id + '"/>
<select class="form-control" name="Skills[0].Level">
<option value="0">None</option>
<option value="1">Know</option>
<option value="2">Understand</option>
<option value="3">Master</option>
</select>
</div>
Because it is dynamic and every time a new skill is created / deleted how can an updated SkillDetails type list be transferred to the controller according to the skills I selected and entered their level?

If you give each instance of a skill in Skills an index value then you can submit a collection of items to the controller. I have something similar in a project although not using JS/Ajax.
Add:
<input type="hidden" name="Skills.Index" id="Skills.Index" value="0" />
for each instance of a skill...where 0 changes to be a unique value for each instance.
Each form field per 'skill' should use this index, so...
<input type="text" name="Skills[0].title" id="Skills[0].title" value="[whatever]" />
<input type="text" name="Skills[0].SkillID" id="Skills[0].SkillID" value="[whatever]" />
and so on...
Then, in the controller you can accept IList<Skill.SkillDetails> Skills from your form submission.

Your Javascript code should include a way to notify the controller that the list of skills is changed.
You could achieve that using a simple Ajax call and a controller method endpoint which will update your back-end repository (the database).
You could try something like:
$eventSelect.on("select2:select", function (e)
{
console.log("select: ", e);
var fieldWrapper = $("<div class=\"fieldwrapper\" id=\"field" + e.params.data.id + "\"/>");
var fType = $('<div class="input-group mb-2"><span class="input-group-prepend"><span class="input-group-text">' + e.params.data.text + '</span ></span ><input type="hidden" name="Skills[0].SkillID" value="' + e.params.data.id + '"/><select class="form-control" name="TEST"><option value="0">None</option><option value="1">Know</option><option value="2">Understand</option><option value="3">Master</option></select></div>');
fieldWrapper.append(fType);
$("#buildyourform").append(fieldWrapper);
// This block of code will convert the content of the skill list to json
// and pass it back to a controller.
var jsonSkills = JSON.stringify([js object containing the list of skills]);
$.ajax({
type: 'POST',
url: '/path/to/your/controller',
data: {
'skillList': jsonSkills
},
success: function(msg){
alert('ok: ' + msg);
}
});
});
Also, about your:
Skills[0].SkillID is just a test and it didn't work and it crashes the
website
That's because you are encoutering a Null Reference Exception since you are not initialising the collection in the controller.

Related

Populate a dropdown with entity database via ajax

As the title says, I'm trying to use ajax to populate a dropdown list from my ApiController and I'm a bit lost. I basically have an entity table that brings back a bunch of department names. After debugging, I know my table is bringing back data as it shows department names coming through. So I think the issue mainly lies within the ajax. When I view the page, the dropdown just says 'nothing selected' and has an empty list. In my ApiController I have:
[RoutePrefix("Api/Request")]
public class NewUserController : ApiController
{
private readonly ZeusEntities _zeus_Entity;
public NewUserController(ZeusEntities zeus)
{
_zeus_Entity = zeus;
}
[Route("Departments")]
[HttpGet]
[CustomApiAuthorize(Roles = UserRole.HR)]
public async Task<IHttpActionResult> GetDepartments()
{
var departments = await _zeus_Entity.DEPARTMENT.Where(z => z.B_DELETE == 0).Select(z => z.S_NAME).Distinct().ToListAsync();
return Ok(departments);
}
}
And in my view, I have:
<div class="form-group col-xs-12 col-sm-4">
<div class="input-group ">
<span class="input-group-addon white">Department</span>
<select class="form-control gray" id="departmentSelect" type="text" </select>
</div>
</div>
Inline:
$.ajax({
type: "GET",
url: "#Url.Action("Departments", "Api/Request")",
data: "{}",
success: function (data) {
var s = '<option value="-1">Please Select a Department</option>';
for (var i = 0; i < data.length; i++) {
s += '<option value="' + data[i].I_PATTERNID + '">' + data[i].S_NAME + '</option>';
}
$("#departmentSelect").html(s);
}
});
Could you please point me in the right direction?
Thanks
So I change the ajax for function to a $.each and realized that I was calling the table column names instead of the variable names I assigned to the data.
$.each(deptList, function (key, department) {
departmentsHtml += "<option value='" + department.DeptId + "'>" + department.Department + "</option>"
});
I feel very silly that I overlooked that bit. Nonetheless, that solved my issue.

Generate city state dropdown based on zipcode entered

I have 2 drop-downs city and state and zip code textbox. I need to generate city and state drop-downs based on zip code entered. When a user enters zip code I am passing zip code to my API to get state/city list.
with the below code I am able to get he data from my API and can see the state/city in the console but i not able to display in drop down. I am not sure what I am missing. How do I display data in drop drown list.
API controller :
public class Getstatelist : ApiController
{
// GET api/Getstatelist/5
public List<CityState> GetCityState(string zipEntered)
{
var list = new List<CityState>();
if (string.IsNullOrEmpty(zipEntered) || zipEntered.Length < 2)
return list;
zipEntered += "%";
using (var connection = new OracleConnection(ConfigurationManager.ConnectionStrings["MY_DB_CONNECTION_STRING"].ConnectionString))
{
connection.Open();
var sqlQuery = "select state from state_city_data where zip like :zipEntered";
using (var command = new OracleCommand(sqlQuery, connection))
{
command.BindByName = true;
command.Parameters.Add("zipEntered", OracleDbType.Varchar2).Value = zipEntered;
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
list.Add(new CityStateZip
{
State = reader["STATE"] != DBNull.Value ? Convert.ToString(reader["STATE"]) : null,
});
}
}
}
}
return list;
}
}
$(document).ready(function ()
{
$("#zip").keyup(function () {
var el = $(this);
if (el.val().length === 5) {
$.ajax({
type:'GET',
url: "../api/Getstatelist/" + el.val(),
success: function (html) {
console.log(html);
$('#state').html(html);
}
});
}else{
$('#state').html('<option value="">Enter Zip code first </option>');
}
});
});
<div>
<div class="city-wrap">
<select id="city">
<option value="">Select City first</option>
</select>
<label for="city">City</label>
</div>
<div class="state-wrap">
<select id="state">
<option value="">Select State </option>
</select>
<label for="state">State</label>
</div>
<div class="zip-wrap">
<input type="text" pattern="[0-9]*" maxlength="5" required name="zip" id="zip" >
<label for="zip">Zip</label>
</div>
</div>
For populating state drop down, u need to modify your success callback in ajax as follows:
$.each(html,function(key,value){
$('#state').append($('<option></option>').val(value.State).html(value.State));
});
For city drop down also similarly:
$.each(html,function(key,value){
$('#city').append($('<option></option>').val(value.City).html(value.City));
});

How to bind an List<IFormFile> property dynamically

My issue is very similar to my previous post:
How to bind a property to a dynamic list of objects
However I am trying to do the same thing that solved this problem in my previous post with a more complex control, an input file selector. Due to this, my question is very similar, however in this case I am guessing the fix is slightly different since the previous solution did not work. Anyhow here goes:
I am using the .net core 2.2 framework and am having trouble finding out how I can bind a list of IFormFile to a razor page. On the razor page I have a button to add a new file input to the screen. This button executes a jquery click event that alters the html to add a new input button of type file without refreshing the page. What I am looking to do with this, is that when I add a new button it binds the selected file to the List object. I can then process this list of items when I post the form.
My Razor Page cs looks something like this:
public class CreateModel : PageModel
{
#region Variables
private readonly MyContext _myContext;
#endregion
#region Properties
[BindProperty]
public List<IFormFile> Files { get; set; }
#endregion
public CreateModel(MyContext myContext)
{
_myContext = myContext;
}
public async Task<IActionResult> OnGetAsync()
{
#region Create instance of a FormFile for testing purposes
FormFile file;
using (var stream = System.IO.File.OpenRead("/test.txt"))
{
file = new FormFile(stream, 0, stream.Length, stream.Name, Path.GetFileName(stream.Name))
{
Headers = new HeaderDictionary(),
ContentType = "text/css",
};
}
Files.Add(file);
#endregion
return Page();
}
public async Task<IActionResult> OnPostAsync()
{
return Page();
}
}
The Razor Page cshtml looks something like this:
...
<div id="file-container">
#for (var i = 0; i < Model.Files.Count(); i++)
{
<div class="myfile">
<label class="control-label">Upload file</label>
<input asp-for="Files[i]" type="file" />
</div>
}
</div>
<div class="item-add">
<a id="add-file" class="link-button"><img class="add-file" src="#Url.Content("~/images/ic_add.png")" />Add File</a>
</div>
and finally here is my jquery code:
$("#add-file").click(function () {
var nextId = $(".file").length;
var rowHtml = '<div class="file">' +
'<label class="control-label">Upload file</label>' +
'<input id="Files_' + nextId + '_" name="Files[' + nextId + ']" type="file" />' +
'</div>';
$("#file-container").append(rowHtml);
});
Finally, when I post the form that contains this code, I want to be able to access the values input into the dynamically created html from my binded property.
If there is anything that is not understood please let me know and I will try clarifying.
So Apparently when you work with input files it appears that you don't use the [i] part as in normal cases. Below is the code that changed:
<div id="file-container">
#for (var i = 0; i < Model.Files.Count(); i++)
{
<div class="myfile">
<label class="control-label">Upload file</label>
<input asp-for="Files" type="file" />
</div>
}
</div>
and in jquery:
$("#add-file").click(function () {
var nextId = $(".file").length;
var rowHtml = '<div class="file">' +
'<label class="control-label">Upload file</label>' +
'<input id="Files" name="Files" type="file" />' +
'</div>';
$("#file-container").append(rowHtml);
});

Data Fetched Not Getting to the Client Side

I have an angular application I am creating where I click a page that fetches data from the database but for some weird reason, does not display on the browser. The operation sort of crashes and I click on this particular page and there are no errors logged anywhere, not even on the console or in a text file designed to log all errors/exceptions.
I debugged the C# code on server side and realized the rows are loaded successfully but it doesn't display on the browser and the operation crashes without an error. Please help me. I don't know what I'm doing wrong. Similar approach of fetching data was used for other pages and they work very well.
Server Side
public PagedResultDto<GoodsRequestDto> GetGoodsRequestPaged(GoodsRequestListInput input)
{
var goodsRequests = _goodsRequestRepo.GetAllIncluding(g => g.GoodsQuotes)
.WhereIf(input.UserId.HasValue, g => g.CreatedBy == input.UserId)
.OrderBy(d => d.Id)
.PageBy(input)
.ToList();
return new PagedResultDto<GoodsRequestDto>
{
TotalCount = goodsRequests.Count,
Items = goodsRequests.MapTo<List<GoodsRequestDto>>()
};
}
Angular Controller
vm.loadGoodsRequests = function () {
var skipCount = 0;
abp.ui.setBusy(null,
projectService.getGoodsRequestPaged({
skipCount: skipCount,
userId: appSession.user.id
}).success(function (data) {
vm.goodsRequests = data.items;
})
);
}
Html
<div ng-if="vm.goodsRequests.length" ng-repeat="gr in vm.goodsRequests" class="classInfo-list-item col-md-6">
<div class="classInfo-body">
<h3 class="classInfo-title">
{{gr.categoryItem.name + "_" + gr.brand.name + "_" + gr.product.name | cut:true:50:' ...'}}
</h3>
<p class="classInfo-description">Quantity: {{gr.quantity}} {{gr.unit}}</p>
<p class="classInfo-description">Payment Term: {{gr.paymentTerm}}</p>
<div class="classInfo-registration-info">
{{gr.goodsQuotes.length}} Quote(s).
</div>
<div class="classInfo-actions">
<a class="btn btn-sm btn-info" ng-href="#/my-goods-requests/{{gr.id}}">#L("Details") <i class="fa fa-arrow-circle-right"></i></a>
</div>
<span ng-class="vm.statusClass(gr.statusString)" class="classInfo-date"> {{gr.statusString }}</span>
</div>
</div>
This is the third day on this issue. I am desperate for some help.
The api is returning Items not items
So try using data.Items
These errors can be easily avoided using browser development tools and the debugger; at the right place ..
hovering on the data variable will show you the structure which is returning at run time

Can't pass select values to controller

I'm having a difficult time passing my Select values on my View to the controller.
I have two items on my view which I wish to return to the model, where I can call in the controller. Heres what I have so far.
<label for="phone" class="ui-hidden-accessible">Phone Number:</label>
#Html.TextBoxFor(m => m.PhoneNumber, new { #class = "field-margin", id="phone", type="tel", placeholder="Phone Number"})
<p></p>
<div><p>Save phone for future purchases?</p>
<select name="SavePhone"id ="SavePhone" class="SavePhone" data-role="select">
<option value="false" #(Model.SavePhone == false ? "selected" : "")>No</option>
<option value="true" #(Model.SavePhone == true ? "selected" : "")>Yes</option>
</select><
I'm not exactly sure how to call the second part for the select options. However the top part of my code which accepts the phone number works. My naming in the model, controller, and view all are the same so I'm not sure what to do next. If you have any suggestions it would be appreciated.
Thanks!
Edit
I figured out a part of my problem, Since I am loading this as
#Html.Partial("MobilePhoneView", Model)
after I click continue on the first page, it loads the view with my two options and hits the select block before it even displays. Is there some kind of work around for this?
You can do this using AJAX. If you have following HTML
<select name="SavePhone"id ="SavePhone" class="SavePhone" data-role="select">
<option value="false">No</option>
<option value="true">Yes</option>
</select>
Then , you can simply use following to sent your choice to controller:
<script language="javascript" type="text/javascript">
$(document).ready(function () {
$("form").submit(function () {
$.ajax({
url: '#Url.Action("MethodName","ControllerName")',
type: 'POST',
cache: false,
data: { Selected: $("#SavePhone").val() },
success: function (data) {
//
}
});
});
)};
</script>
You will get this value in the controller
private string MethodName (string Selected)
{
String value = Selected;
return "OK";
}
The only possible problem with your code might be with selected attribute. Not all browsers understand just selected (I believe this is HTML5 way of setting such attributes), though all should understand selected="selected". So what you can try is:
<select name="SavePhone"id ="SavePhone" class="SavePhone" data-role="select">
<option value="false" #(Model.SavePhone == false ? "selected=\"selected\"" : "")>No</option>
<option value="true" #(Model.SavePhone == true ? "selected=\"selected\"" : "")>Yes</option>
</select>

Categories

Resources