MVC 5 - Registering JavaScript events from partial view which uses BeginCollectionItem - javascript

I have a partial view which looks like this:
#model Whatever.Models.Jobs
#using (Html.BeginCollectionItem("JobRecords"))
{
<tr id="jobRow">
#Html.HiddenFor(m => m.Id)
<th width="40%">
#Html.EditorFor(m => m.Project, new { htmlAttributes = new { #class = "form-control", id = "project", list = "projectResults" } })
<datalist id="projectResults"></datalist>
#Html.ValidationMessageFor(m => m.Project, "", new { #class = "text-danger" })
</th>
</tr>
}
This is embedded in the parent view like:
#if (Model.JobRecords != null)
{
foreach (var item in Model.JobRecords)
{
Html.RenderPartial("_JobEditorRow", item);
}
}
It all works, but as you can see from the partial view I want to add a searchable box using data-list, so I add a method in my controller:
[HttpGet]
public JsonResult GetProjects(string query)
{
var list = unitOfWork.ProjectRepository.Get(c => c.Name.contains(query));
var serialized = list.Select(p => new { p.ProjectCode, p.Name});
return Json(serialized, JsonRequestBehavior.AllowGet);
}
And then add some javascript which uses AJAX to populate this data-list:
$(document).ready(function () {
var delay = 1000;
var globalTimeout = null;
function contractsCall() {
console.log("called");
$("#projectResults").empty();
$.ajax({
cache: false,
type: "GET",
contentType: "application/json;charset=utf-8",
url: "/MyController/GetProjects?query=" + $("#project").val()
})
.done(function (data) {
if (data[0] !== undefined) {
for (var i = 0; i < data.length; i++) {
$("#projectResults").append(
"<option value=" + data[i]["ProjectCode"] + ">" + data[i]["Name"] + " - " + data[i]["ProjectCode"] + "</option>"
);
}
} else {
$("#projectResults").empty();
}
});
}
$("#project").keyup(function (event) {
console.log("keyup");
if (globalTimeout !== null) {
clearTimeout(globalTimeout);
}
globalTimeout = setTimeout(function () {
globalTimeout = null;
contractsCall();
}, delay);
});
});
This javascript is included in the parent view which is also embedding the partial view. But I add a job record and type something in the input box, it doesn't do anything despite it having the id of project.
My question is, how can I register events that occur in partial views from a parent view; or if I could embed by javascript file in the partialview to fix this? And the more difficult question is, how can I prevent the duplication of ids when adding a job with BeginCollectionItem? Because adding multiple rows would add multiple project id input boxes.
Update
#Stephen helped me greatly to fix this issue, I removed the <datalist> tag from the partial view and placed it in the main view, and used class instead of id. Then I changed my JS to something like this:
$("body").on("keyup", ".projectField", function () {
var self = $(this);
if (globalTimeout !== null) {
clearTimeout(globalTimeout);
}
globalTimeout = setTimeout(function () {
globalTimeout = null;
contractsCall(self.val());
}, delay);
});
This way I can search using my AJAX call for $(this) input box. The other issue I had was seeing which input box was clicked so I can update some other things, for this I used:
document.querySelectorAll('input[list="projectResults"]').forEach(function (element) {
element.addEventListener('input', onInput);
});
Which calls:
function onInput(e) {
var input = e.target,
val = input.value;
list = input.getAttribute('list'),
options = document.getElementById(list).childNodes;
var row = $(this).closest("tr");
var p = row.find(".projDescription");
for (var i = 0; i < options.length; i++) {
if (options[i].value === val) {
$.ajax({
cache: false,
type: "GET",
contentType: "application/json;charset=utf-8",
url: "/ContractProject/GetProjects?query=" + val;
})
.done(function (data) {
if (data[0] !== undefined) {
console.log(data[0]["WorksDescription"]);
p.text(data[0]["WorksDescription"]);
}
});
break;
}
}
}
It's a little bit counter intuitive because I am making 2 AJAX calls but the second one isn't going to be heavy as it's asking for a specific element.

Related

How to set value programmatically to Select2 jQuery & ASP .Net Core

I'm working on a ASP .Net Core project where for the first time I'm using Select2.
I have one page where I'm passing the ID's that I need by ViewModel like this:
Controller:
public async Task<IActionResult> MyPage()
{
var model = new MyViewModel()
{
selectedUSerId = 1,
selectedEmployeeId =1
};
return View(model);
}
View:
#model MyViewModel
<select class="form-select" id="User" name="User" data-url="#Url.Action("MyUserAction","MyUserController")" data-placeholder="#Localizer["SelectUser"].Value">
<option></option>
</select>
<select class="form-select" id="Employee" name="Employee" data-url="#Url.Action("MyEmployee","MyEmployeeController")" data-placeholder="#Localizer["SelectUser"].Value">
<option></option>
</select>
#section Scripts{
<script type="text/javascript">
var userId = "#Model.selectedUSerId";
var emplyeeId = "#Model.selectedEmployeeId";
$(document).ready(function () {
$('select').each(function () {
InitSelect2(this.id);
});
if(userId){
$('#User').val(userId).trigger('change');
}
if(emplyeeId){
$('#User').val(emplyeeId).trigger('change');
}
});
function InitSelect2(selector, selectedId = 0) {
var url = $("#" + selector).data('url');
var placeholder = $("#" + selector).data('placeholder');
const type = "POST";
const dataType = "json";
if (!url) {
console.error("Selector: " + selector + " Unspecified URL");
return;
}
if (placeholder === "") {
console.error("Selector: " + selector + " Unspecified Placeholder");
return;
}
try {
$("#" + selector).select2({
theme: "bootstrap-5",
width: $(this).data('width') ? $(this).data('width') : $(this).hasClass('w-100') ? '100%' : 'style',
placeholder: placeholder,
allowClear: true,
minimumInputLength: 3,
ajax: {
url: url,
type: type,
dataType: dataType,
delay: 250,
data: function (params) {
var query = {
id: selectedId,
searchFullName: params.term,
}
return query;
},
processResults: function (data) {
console.log(data)
return {
results: data.results
};
},
}
})
} catch (ex) {
console.error(ex);
}
}
</script>
}
So far it works perfectly.
But when I try to do:
$('#User').val(userId).trigger('change'); or
$('#Employee').val(emplyeeId ).trigger('change');
nothing happened.
I think its gonna work only when I retrieve the data the first time when I click the drop donw list, instead of doing it every time when it is clicked.
In that way I will have the <option>s and I can use the jQuery to select the <option> by Id.
I don't like to follow this approach, becouse the data should be load and setted dynamically. Theres no another way to do it?
If you want to do something only when first time the selected value is changed,you can try to use a js variable,change the value of it when first time the selected value is changed.Here is a sample,only when first time the selected value is changed,alert(1) will be called.
var UserCount = 0;
var EmplyeeCount = 0;
$('#User').change(function() {
if (UserCount == 0) {
UserCount++;
alert(1);
}
});
$('#Employee').change(function() {
if (EmplyeeCount == 0) {
EmplyeeCount++;
alert(1);
}
});

A script for upadate textbox's value in asp.net mvc didn' work

I want to update textbox's value(that contains cookie's value) using Ajax in asp.net MVC5 . I'm very new in JavaScript and I wrote these codes , but my code didn't work . I didn't get any error but it's not working. I wrote JavaScript in foreign file 'UpdateTxtBox.js' and I added <script src="~/Scripts/UpdateTxtBox.js"></script> to Layout .
Could anyone tell me what's the problem ?
$(function () {
$("textCountProduct").change(function () {
var count = $(this).val();
var id = $(this).attr("productid");
$.ajax({
url: "/Goods/AddToCart",
data: { Id: id, Count: count },
type: "Post",
dataType: "Json",
success: function (result) {
if (result.Success) {
alert(result.Html);
$("#CartItems").html(result.Html);
}
eval(result.Script);
},
error: function () {
alert("error....");
}
});
});
});
a part of Basket.cshtml
#using (Html.BeginForm("AddToCart", "Goods", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.TextBoxFor(modelItem => item.Count, new { #class="text textCountProduct" , style="width:40px;" , productid=item.GoodDetails.DetailsGoodID})
}
Good controller
public ActionResult AddToCart (int Id , int Count)
{
try
{
if (Request.Cookies.AllKeys.Contains("NishtmanCart_" + Id.ToString()))
{
//Edit cookie
var cookie = new HttpCookie("NishtmanCart_" + Id.ToString(), (Convert.ToInt32(Request.Cookies["NishtmanCart_" + Id.ToString()].Value) + 1).ToString());
cookie.Expires = DateTime.Now.AddMonths(1);
cookie.HttpOnly = true;
Response.Cookies.Set(cookie);
}
else
{
//Add new cookie
var cookie = new HttpCookie("NishtmanCart_" + Id.ToString(), Count.ToString());
cookie.Expires = DateTime.Now.AddMonths(1);
cookie.HttpOnly = true;
Response.Cookies.Add(cookie);
}
List<HttpCookie> lst = new List<HttpCookie>();
for (int i = 0; i < Request.Cookies.Count; i++ )
{
lst.Add(Request.Cookies[i]);
}
bool isGet = Request.HttpMethod == "GET";
int CartCount = lst.Where(p => p.Name.StartsWith("NishtmanCart_") && p.HttpOnly != isGet).Count();
return Json(new MyJsonData()
{
Success = true,
Script = MessageBox.Show("Good added successfully", MessageType.Success).Script,
//Script = "alert('Good added successfully');",
Html = "cart items (" + CartCount.ToString() + ")"
}
);
}
Update post :
I added [HttpPost] to controller action result and add some alert to javascript
$(function () {
alert("aleeeert");
$(".textCountProduct").change(function () {
var count = $(this).val();
var id = $(this).attr("productid");
alert(count);
alert(id);
$.ajax({
url: "/Goods/AddToCart",
data: { Id: id, Count: count },
type: "Post",
dataType: "Json",
success: function (result) {
if (result.Success) {
alert(result.Html);
$("#CartItems").html(result.Html);
}
eval(result.Script);
},
error: function () {
alert("error....");
}
});
});
});
it's working fine but when I refresh page , data didn't saved
Since you have specified textCountProduct as CSS class, you need to prefix it with . to use Class Selector (“.class”), As of now its looking for Element textCountProduct which obviously doesn't exists.
Use
$(".textCountProduct").change(
You have made mistake here $("textCountProduct") use . as selector.
It should be $(".textCountProduct")
and
Check path of your script included
<script src="~/Scripts/UpdateTxtBox.js"></script>

DropDownList Children Binding

I have an issue with a dropdownlist and I can't figure it out how to solve it.
There are two different way to get into my view: Add New and Edit.
1) Add New: In this situation my dropdownlist is related to another one, and everything works great.
the dropdownlist is locked and empty until I select something in the other one.
2) Edit: In this situation my dropdownlist is already binded using stored data. Of course if I change the selected item in the "parent" one I want to change data to the children too.
The problem appears in the 2 case: When I select something else out of the stored data in the related dropdownlist.
It binds the correct data, but it gives an empty item as first, and not the first of the data.
How can I solve it?
<%=Html.Kendo().DropDownListFor(model => model.GNR_FK)
.Name("GNR_FK") .BindTo((IEnumerable<Models.Widget.Combo>)ViewData["Customer"])
.DataTextField("descriptionText")
.DataValueField("valueID")
.Value(Model.GNR_FK.ToString())
.Events(e =>
{
e.Select("onSelect");
})
%>
<%=Html.Kendo().DropDownListFor(model => model.CNT_FK) .BindTo((IEnumerable<Models.Widget.Combo>)ViewData["Sender"])
.Name("CNT_FK")
.DataTextField("descriptionText")
.DataValueField("valueID")
%>
Condition:
if (Model.PK == 0)
{
loadValues(current);
}
else
{
loadEditValues(current);
}
public JsonResult loadValues(Models.Model current, int PK = 0)
{
IDataReader sender = Model.getSender(PK);
Models.Widget.Combo SenderNA = new Models.Widget.Combo();
List<Models.Widget.Combo> receiveSender = new List<Models.Widget.Combo>();
SenderNA.valueID = 0;
SenderNA.descriptionText = "NA";
receiveSender.Add(SenderNA);
while (sender.Read())
{
Models.Widget.Combo newItem = new Models.Widget.Combo();
newItem.valueID = int.Parse(sender["PK"].ToString());
newItem.descriptionText = sender["SURNAME"].ToString();
receiveSender.Add(newListItem);
}
return Json(receiveSender, JsonRequestBehavior.AllowGet);
}
private void loadEditValues(Models.Model current)
{
int selected = current.GNR_FK;
IDataReader sender = current.getSender(selectedCustomer);
Models.Widget.Combo SenderNA = new Models.Widget.Combo();
List<Models.Widget.Combo> receiveSender = new List<Models.Widget.Combo>();
SenderNA.valueID = 0;
SenderNA.descriptionText = "NA";
receiveSender.Add(SenderNA);
while (sender.Read())
{
Models.Widget.Combo newItem = new Models.Widget.Combo();
newItem.valueID = int.Parse(sender["PK"].ToString());
newItem.descriptionText = sender["SURNAME"].ToString();
receiveSender.Add(newListItem);
ViewData["List"] = receiveSender;
}
}
Script:
function onSelect(e) {
var dataItem = this.dataItem(e.item);
var PK = dataItem.valueID;
$.ajax({
type: 'POST',
url: '/Project/loadValues',
data: "{'PK':'" + PK + "'}",
contentType: 'application/json; charset=utf-8',
success: function (result) {
$("#CNT_FK").data("kendoDropDownList").dataSource.data(result);
},
error: function (err, result) {
alert("Error" + err.responseText);
}
});
}
Regards
Problem Solved!
It was missing the select method to automatically select the first item after changing data!
success: function (result) {
var dropdown = $("#CNT_FK").data("kendoDropDownList");
dropdown.dataSource.data(result);
dropdown.select(0);
},

MVC Html.ActionLink parameter values not being passed

I'm testing MVC for a demo and I managed to scrap together some pieces but now I am having trouble with an Html.ActionLink. The intent is to present the user with a series of dropdownlists that they must select before the ActionLink is shown. To do that I've copied some JQuery to hide/show my dropdownlists (as selections are made) and the ActionLink. I added an alert to my JQuery to check my values and via the alert it all looks good. But if I debug the controller the parm values are defaulted to 0. I'm not sure what code to include but I will try to include the relevant parts. I think it's something basic.
Here are the dropdown lists and ActionLink.
#Html.DropDownListFor(m => m.selected_env_ID, new SelectList(Model.Environments, "env_ID", "env_DESC"), "*Select an environment")
#Html.DropDownListFor(m => m.selected_app_ID, new SelectList(Model.Applications, "app_ID", "app_DESC"), "*Select an application",new { #hidden = "hidden" })
#Html.DropDownListFor(m => m.selected_job_ID, Enumerable.Empty<SelectListItem>(), "*Select a job", new { #hidden = "hidden" })
#Html.ActionLink("Submit", "Submit", new { id = Model.selected_job_ID, envid = Model.selected_env_ID }, new {id = "lnkSubmit" })
Here is the convoluted JQuery to hide/show and fill the cascading dropdowns.
<script>
$(document).ready(function ()
{
//Dropdownlist Selectedchange event
$("#selected_app_ID").change(function () {
var id = $('#selected_app_ID').val(); // id value
if (id == 0) {
$('#selected_job_ID').hide();
} else {
$('#selected_job_ID').show();
$("#selected_job_ID").empty();
$.ajax({
type: 'POST',
url: '#Url.Action("SelectJobs")',
dataType: 'json',
data: { id: $("#selected_app_ID").val() },
success: function (jobs) {
// jobs contains the JSON formatted list of jobs passed from the controller
$("#selected_job_ID").append('<option value=0>*Select a job</option>');
$.each(jobs, function (i, job) {
$("#selected_job_ID").append('<option value="'
+ job.job_ID + '">'
+ job.job_DESC + '</option>');
});
},
error: function (ex) {
alert('Failed to retrieve jobs.' + ex);
}
});
}
return false;
});
//ddl select change
$("#selected_env_ID").change(function () {
var name = $('#selected_env_ID option:selected').text(); //Item1
var id = $('#selected_env_ID').val(); // id value
if (id == 0) {
$('#divSubmit').hide();
$('#selected_app_ID').hide();
$('#selected_job_ID').hide();
} else {
$('#selected_app_ID').show();
}
});
//ddl select change
$("#selected_job_ID").change(function () {
var name = $('#selected_job_ID option:selected').text(); //Item1
var id = $('#selected_job_ID').val(); // id value
var envid = $('#selected_env_ID').val(); // id value
if (id == 0) {
$('#divSubmit').hide();
} else {
$('#divSubmit').show();
alert("envid=" + envid + " jobid=" + id);
}
});
}); // end document ready
</script>
My controller has this and id and envid end up being 0:
public ActionResult Submit(int id = 0,int envid = 0) {
If I need to include something else just let me know.
Here is the method that fills the job dropdown list. This works without issues. It's the Html.ActionLink call to Submit that fails to include the parameters.
public JsonResult SelectJobs(int id)
{
db.Configuration.ProxyCreationEnabled = false;
IEnumerable<t_job> jobs = db.t_job.Where(j => j.app_ID == id).ToList();
return Json(jobs);
}
Your link
#Html.ActionLink("Submit", "Submit", new { id = Model.selected_job_ID, envid = Model.selected_env_ID }, new {id = "lnkSubmit" })
is rendered on the server side before you make any selection in the dropdowns. If the initial values of selected_job_ID and selected_env_ID are zero or null, then those values will be passed to the controller (have a look at the rendered html).
If you want to pass the values selected in you drop downs, you could either modify the links href attribute in the drop down change events, or create a button instead of a link, and do a redirect in the buttons click event based on the dropdown values.
You need to use JSON.stringify():
data: JSON.stringify({ id: $("#selected_app_ID").val() }),

Cascading dropdown lists in Mvc 4.0

I have been trying to cascade dropdown lists. For this purpose I am using javascript in .cshtml page . Don't know what is the reason , I'm not able to even call Js method , leave alone the controller method which later needs to be called from within the Js method. Dropdowns are fetching the state and city data but I'm not getting the city according to the state selected.
<div class="editor-label">
#Html.LabelFor(model => model.State_Id)
</div>
<div class="editor-field">
#Html.DropDownList("State",null,"Select State", new {#class="span4", id="State"})
#Html.ValidationMessageFor(model => model.State_Id)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.CityId)
</div>
<div class="editor-field">
#Html.DropDownList("City",null,"Select City", new {#class="span4", id="City"})
#Html.ValidationMessageFor(model => model.CityId)
</div>
<script src="~/Scripts/jquery-1.7.1.js"></script>
<script src="~/Scripts/jquery-1.7.1.min.js"></script>
<script type="text/javascript" >
$(document).ready(function(e) {
$("#State").change(function (e) {
var selectedValue = $(this).val();
if(selectedValue != "Select") {
$.ajax({
url: '#Url.Action("GetCities","Employer")',
type: 'Post',
//data: { "selectedValue": selectedValue},
data: {id: $("#State").val()},
dataType: 'json',
success: function(response) {
var items = "";
$.each(response, function(i, city) {
$("#City").append('<option value="' + city.Value + '">' + city.Text + '</option>');
});
},
error: function (ex) {
alert("Failed To Receive States" + ex);
}
});
}
});
});
</script>
#Html.DropDownListFor(x => x.LeagueId, Model.LeagueSL, "--Select League--", new { id = "ddlLeague"})
#Html.DropDownListFor(x => x.LeagueId, Model.DivisionSL, "--Select Division--", new { id = "ddlDivision"})
The Second DropDownList is empty, all it has is the option Label --Select Division--
On change event of the 1st dropdown make an AjaxRequest that fills the Second One.
var value = $("#DropDown1").val();
var ddlDivision = $("#DropDownDivision");
ddlDivision.html('');//clear current contents;
$.ajax({
url: "/Home/GetDivisions",
type: "GET",
data: { leagueId: value },
success: function (data) {
$.each(data, function (index, item) {
//item = this
//populate ddl
ddlDivision.append($('<option></option>')
.val(item.PropTwo)
.html(item.PropOne));
});
});
public JsonResult GetDivisions(int leagueId)
{
using (BaseballEntities context = new BaseballEntities())
{
var divisions = (from x in context.Table
where x.LeagueID == leagueId
select new
{
PropOne = x.DivisionName,
PropTwo = x.DivisionId
}).ToList();
return Json(divisions, JsonRequestBehavior.AllowGet);
}
}
Edit: As a Side Note it is better to use your Model to fill your dropdownList.
Give your model a SelectList property
public List<SelectListItem> LeagueSL { get; set; }//you will need to initialize in constructor
public ActionResult Index()
{
MyViewModel model = new MyViewModel();
using (MyEntities context = new MyEntities())
{
var leagueList = context.League.ToList();
foreach (var item in leagueList)
{
model.LeagueSL.Add(new SelectListItem() { Text = item.LeagueName, Value = item.LeagueId.ToString() });
}
}
return View(model);
}
Drop down lists are their own beast. You probably need to create the new OPTIONs using standard DOM methods inside the loop rather than jQuery's append method:
success: function(response) {
var items = "", option, $city = $("#City");
$.each(response, function(i, city) {
option = document.createElement("option");
option.value = city.Value;
option.innerHTML = city.Text;
$city.append(option);
});
},

Categories

Resources