change event stops firing after jqueryui popups opened and closed - jquery-ui-dialog

Here's the short TL;DR version:
I have an onchange event against a select list that stops firing
Is there any issue using JQuery against an element id i.e. $("#Customer_ID").change, if that element is inside a jqueryui popup that is populated from a partial view. Further to this I have two different popups populated by different partial views that share the same $("#Customer_ID").change javascript
I have a page with two divs for jquery ui popups
When I click in a cell in jqgrid, I popup the appropriate dialog (Edit or New)
The popups are in turn populated by a partial view from a controller
This works fine
I have three levels of cascading drop downs in these popups. Most of the time they work correctly. After a few opens and closes of the popups however the dynamic drop downs stop working
At this point the dynamic drop down jscript is being loaded OK but it seems the change event is not being fired.
I suspect it's because I have two popups with identically named controls?
Anyway here is some abridged code fragments
_Layout.cshtml
Has a reference to the js that attaches all the JQueryui stuff
<!-- Logic to setup edit,new,delete popups -->
<script src="~/Scripts/Layout.js" type="text/javascript"></script>
Layout.js
Contains code to set up the edit popup and some other things. Here's just the part for the create popup:
$("#dialog-create").dialog({
title: 'New',
autoOpen: false,
resizable: true,
width: 800,
height: 440, // this allows the dialog to correctly estimate the middle of the viewport
show: { effect: 'fade', duration: 100 },
modal: true,
open: function (event, ui) {
if (urlNew) $(this).load(urlNew);
},
});
TasksWeeklyClient.cshtml
This actually has a jqGrid on it. Clicking on a cell pops up, for example the create popup.
<!-- edit, new, delete popups -->
<div id="dialog-edit" style="display: none; z-index: 2000;">
</div>
<div id="dialog-create" style="display: none; z-index: 2001;">
</div>
Create.cshtml
This is fed by a controller that returns a partial view. This is where the problems start. The Customer_ID drop down cascades to the CustomerProject_ID drop down. After a few closes and opens it stops working though. This also has a reference to TasksDialogs.js which has all the cascading drop down stuff (The cascading drop down is the subject of another question here: cascading drop downs repeatedly populated
(this code is found in tasks view folder)
<div class="form-group">
#Html.LabelFor(model => model.Customer_ID, "Customer & Project", htmlAttributes: new { #class = "control-label col-md-6 text-md-left" })
<div class="col-md-12">
#Html.DropDownList("Customer_ID", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.Customer_ID, "", new { #class = "text-danger" })
</div>
<div class="col-md-12">
#Html.DropDownList("CustomerProject_ID", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.CustomerProject_ID, "", new { #class = "text-danger" })
</div>
TaskDialogs.js
Finally we have this script. Normally this works but after a few popup opens and closes, CustomerID.change no longer appears in the console.
You can see I've tried two different ways of attaching the change event. Both exhibit the same symptom.
$(document).ready(function () {
console.log("TasksDialog.js ready");
console.log($("#Customer_ID"));
//When Customer is changed reload Project
// Project function reloads project tasks
$("#Customer_ID").on("change",
// $("#Customer_ID").change(
function () {
console.log("CustomerID.change");
// refresh projects
refreshProjectFromClient();
}
);
I don't know that I need to post controller code. That part all works fine.

In the javascript that manages the dynamic drop downs I was using
$("#Customer_ID")
to refer to fields on two different dialogs.
Turns out I need to use these instead, to specifically refer to the field I want:
$(div#dialog-create #Customer_ID")
$(div#dialog-edit #Customer_ID")
I think possibly the change event is not being attached properly for the same reason. For now I got around it by hard coding the change into the control in the cshtml view like this:
#Html.DropDownList("Customer_ID", null,
htmlAttributes:
new {
#class = "form-control",
#onchange= "refreshProjectFromClient()"
})

Related

Html.EditorFor how to make textbox active on page load

I am working on a site in ASP.NET MVC and I have multiple Html.EditorFor form textboxes. The simple user friendly action I would like to do is on page load, the first of the textboxes on my view page is "active" or the user does not have to click on the textbox to start typing. There are pages like the login or other pages with only these forms where having to click to start typing is not intuitive and breaks the users experience.
Example form:
#Html.EditorFor(model => model.MaxBid, new { htmlAttributes = new { #class = "form-control" } })
I am not finding any documentation for how to accomplish this, but it seems like it could be a simple fix. Thank you for any and all help.
Add autofocus to the elment.
#Html.EditorFor(model => model.MaxBid, new { htmlAttributes = new { #class = "form-control", autofocus = true } })

Kendo Tabstrip with dynamic content in a Partial View

I am new to ASP.NET MVC. I am facing one or other issues to design the layout for below scenario. Could you someone help me with a solution and I will definitely appreciate your help.
The requirement is:
This is an existing application. While loading view there is a Master View and inside few partial views already defined.
In one of the Partial view, I need to have a same layout multiple times on demand. It is depends on the user how many required. may be 1 or 2 or more. We are using Telerik Kendo controls extensively in our UI and in existing View we strongly typed Model object with View.
I would like to go with Kendo Tabstrips control and add Tab dynamically when required by the user. Also, the layout is exactly same, So, would like to design (Html table with many controls like textbox, dropdown etc.) each tab layout as Partial View so that I can reuse the design. Please let me know whether this approach is best or any better approach is available.
I need to get the entire data when the user Submit the master view . Each main partial View contains and the parent of the Tabstrips Partial view also contains a but not defined for each tabstrip partial view as I need data as collection of objects in one of the property in Parent Partial View Model Object.
Can you please let me know how to design model object for each tabs(Partial View) as well as Parent Partial View. it could be good, if you could show a small example code.
The below are the issues faced during designing this
Unable to add inside another as getting below error
Inline markup blocks (#Content) cannot be nested. Only one level of inline markup is allowed.
#(Html.Kendo().PanelBar().Name("panelBar_" + panelName).Items(pb => pb.Add().Text("PCG").Expanded(Expanded).Selected(true)
.Content(#<text>
<form id="frm_#(panelName)" onsubmit="DisableEvent(event)">
<div style="width:100%; height:auto;">
<button class="k-button">Add new PCG</button>
#(Html.Kendo().TabStrip()
.Name("TabPCG").HtmlAttributes(new { style = "width:100%;" })
.Items(items =>
{
items.Add()
.Text("PCG 1 <button data-type='remove' class='k-button k-button-icon' onclick='deleteMe(this)'><span class='k-icon k-i-close'></span></button>")
.Encoded(false)
.Selected(true)
.HtmlAttributes(new { style = "width:12%", id = "tabPCG1" })
//.LoadContentFrom("_PCGTab", "Home", new { tabId ="tab1"});
.Content(#<text>#(Html.Partial("_PCGTab"))</text>);
})
)
</div>
</form>
</text>)))
2.Then Changed the design as shown below. defined partial view in Parent View
#helper RenderPCGTab()
{
<div style="width:100%; height:auto;">
<button class="k-button">Add new PCG</button>
#(Html.Kendo().TabStrip()
.Name("TabPCG").HtmlAttributes(new { style = "width:100%;" })
.Items(items =>
{
items.Add()
.Text("PCG 1 <button data-type='remove' class='k-button k-button-icon' onclick='deleteMe(this)'><span class='k-icon k-i-close'></span></button>")
.Encoded(false)
.Selected(true)
.HtmlAttributes(new { style = "width:12%", id = "tabPCG1" })
//.LoadContentFrom("_PCGTab", "Home", new { tabId ="tab1"});
.Content(#<text>#(Html.Partial("_PCGTab"))</text>);
})
)
</div>
}
and designed Kendo panel as shown below the Parent Partial View
#(Html.Kendo().PanelBar().Name("panelBar_" + panelName).Items(pb => pb.Add().Text("PCG").Expanded(Expanded).Selected(true)
.Content(#<text>
<form id="frm_#(panelName)" onsubmit="DisableEvent(event)">
#RenderPCGTab()
</form>
</text>)))
Since you use a strongly typed View, I would recommend using a Tuple as the model.
The Item1 would hold the required model details, while Item2 would hold the required number of tabs (it holds the names of the tabs).
#model Tuple<[Model],List<string>>
Now create a Kendo Tabstrip control, with dynamic items (based on model's Item2)
#(Html.Kendo().TabStrip()
.Name("KendoTabStrip") //You need to dynamically change the name by appending a unique parameter in case you need multiple Tabstrips
.Animation(animation =>
animation.Open(effect =>
effect.Fade(FadeDirection.In)))
.Items(tabstrip =>
{
var TabItemIndex = 0;
foreach (var TabItem in Model.Item2)
{
tabstrip.Add().Text(TabItem)
.Selected(false)
.HtmlAttributes(new { id = "TabStripButton" + TabItem + "_" + TabItemIndex, title = TabItem}) //Generate a dynamic ID for each Tab
.Content(" ");
TabItemIndex++;
}
})
)
Once you have created the structure of the Tabstrip, you need to populate each tab with its corresponding content
In the View (Parent Partial View) itself, create a Ready function for the tabstrip and serialize the object using JSON
$(("KendoTabStrip")).ready(function () {
_TBSModelName = #Html.Raw(JsonConvert.SerializeObject(this.Model.Item1))
TabStripUserControl();
});
Note: This is in case you need the Model Data in your child partial view.
Create a javascript file and place the function TabStripUserControl() in it. This function will create your content and place it into the tab.
function TabStripUserControl()
{
var _LocalTBSModel = _TBSModelName
var items = "#KendoTabStrip" + " .k-tabstrip-items";
$(items).click(function (z) {
}
);
}
Inside the function (click function), create a div and provide a dynamic ID for the same before placing it inside the tab using Javascript/JQuery.
var div = $("<div/>");
Use Ajax call to call your controller, which in turn will call your Child Partial View (which contains HTML controls) and render the partial view inside the above created div on Ajax call's success.
$.ajax({
url: 'Controller/ActionMethod',
data: JSON.stringify({ Value: "SomeValue" }),
type: 'POST',
contentType: 'application/json;',
async: false,
success: function (data) {
div = data;
}
});
Hope this helps.

Reload PartialView from jQuery in ASP.NET MVC 2 application?

I'm trying to use jQuery to load a PartialView. It does this fine at the first loading of the page. But then I need to be able to reload the PartialView when a save button is pressed. I get a reload, but this time the PartialView is all I get back. I.e. I don't get the PartialView loaded as a part of the main page, but rather as a page of its own. What am I doing wrong?
Here are the relevant parts of the jQuery in the View:
$.get('<%=Url.Action("GetTasks", "Timesheet", new {id = DateTime.Today.ToShortDateString() }) %>', function (data) {
$('#tasksDiv').html(data);
}); //This part works fine on first load of the page
$('#savenewtask').click(function (event) {
event.preventDefault();
$.get('<%=Url.Action("GetTasks", "Timesheet", new {id = DateTime.Today.ToShortDateString() }) %>', function (data) {
$('#tasksDiv').html(data);
});
}); //This only loads the PartialView, but not as part of the main page...
The button and the div to load in:
<p>
<input type="button" value="Spara" id="savenewtask" />
</p>
<div id="tasksDiv">
</div>
UPDATE:
It actually worked, I had just confused the two input fields I have on the page. But I'll rephrase the question to a simple one: Is this the best way to do this sort of thing with PartialViews, or should I go about it another way? (I.e. I was just trying to figure out a way to achieve what I wanted without knowing if it is the "best practice" way of doing it).
I have typically used the load method, which sets the innerHtml.
var url = '<%=Url.Action("GetTasks", "Timesheet", new {id = DateTime.Today.ToShortDateString() }) %>'
$("#tasksDiv").load(url);

ASP.net MVC 2 SPARK - Create "Add New Item" link in spark page

I have a web form in SPARK which allow the editing of a Facility class that contains Rooms. When editing the Facility all the Rooms are listed for editing too. The form works fine for editing, but I would like to include a button "Add Room" that adds a new blank room below the existing ones. Any idea how this is accomplished?
Currently I am doing this in my SPARK page:
[All the Facility editing stuff...]
<p>Room</p>
<div class="small">Enter the rooms associated with this facility.</div>
<div class="add">
<div id="room">
<AddFacilityRoom each="var roomModel in Model.FacilityRooms" RoomModel="roomModel" Index="roomModelIndex" />
</div>
<a id="addRoom" class="add" href="events/room/add.mvc">Add a room</a>
</div>
AddFacilityRoom contains the html elements for editing a room.
I would like add.mvc to create a new empty Room class and inject a new identical (but empty) control below the existing ones. Currently, though it opens a new page when the "Add a Room" button is clicked.
Ok, I figured this out. I was missing the JQuery knowledge to understand this. The function below:
$('#addRoom').click(function () {
var a = $(this);
a.addClass('loading');
$.ajax({
url: a.attr('href'),
cache: false,
success: function (html) {
$('#room').append(html);
a.removeClass('loading');
}
});
return false;
});
Plus, the following HTML:
<div id="room">
<a id="addRoom" class="add" href="events/room/add.mvc">Add a room</a>
</div>
Does the trick.
Your solution looks nice, but since you are using Spark, you could consider the rarely mentioned Javascript templates. The advantage of this being that the markup in _AddFacilityRoom.spark would not need to be duplicated in add.mvc. Nor would a json request be required (if no data needed for new room).
I'll sadly forgotten exactly how they work, but the steps are something like:
Add a new action:
public ActionResult AddRoomScript()
{
return new JavascriptViewResult { ViewName = "_AddFacilityRoom" };
}
Add a script tag with: src="!{Url.Action("AddRoomScript")}"
Then some js to call and set:
var html = Spark.Shared._AddFacilityRoom.RenderView( { RoomModel = {} );
$('#room').append(html);
Some research would be needed to get that working correctly, but it's an interesting option.

Model Binding With Disabled Textbox

I have a textbox that I am defining as
<%= Html.TextBox("Username", Model.Form.Username,
new { #class = "textbox", #disabled = "disabled" })%>
The action is defined as
[AcceptVerbs(HttpVerbs.Post)]
[ValidateAntiForgeryToken]
public ActionResult EditLogin(LoginForm post) {
...
return View(model);
}
When I POST to this, Username will be blank. All other properties bind correctly, but if I change #disabled="disabled" to #readonly="readonly" the username binds properly and everything works.
It looks like model binding ignores values in disabled fields. Is there a way around this? I still need the field's value to bind to the model. I can use readonly but would prefer to use disabled so it is visually apparent to the user that they cannot edit the value of the field.
I believe a form field that is disabled does not submit anything. If you have a form and disable the foo field in that form, when you post the post will not have the value for the foo field. This is simply the nature of disabling a field in HTML and is not a MVC issue.
use readonly - will disable input but you'll still have it in the binding.
You could apply a style on the div to make it looked greyed out maybe?
<div class="editor-label">
#Html.LabelFor(model => model.FileName)
</div>
<div class="editor-field-greyed-out">
#Html.TextBoxFor(model => model.FileName, new { #readonly = true })
#Html.ValidationMessageFor(model => model.FileName)
</div>
If you want the value to be sent back, but not be editable, consider placing it in a hidden field. Obviously, don't do this for anything that requires a degree of security, since a user can tamper with it.
You can do a workaround by adding a hidden field with the same value ;)
<%= Html.Hidden("Username", Model.Form.Username)%>
As suggested in the comments, readonly instead of disabled can be an option but it will not work for select boxes. Instead of creating a hidden input, you can keep the inputs or selects as disabled and still pass the data by changing the disabled property with JavaScript at the submit.
Using jQuery it'd look like this:
$('form').on('submit', function(){
$('input, select').prop('disabled',false);
return true;
});
Easiest way to submit disabled fields is to copy them over to an invisible, non disabled control before submit. Some people create those controls manually and hook up to the on change event in jQuery to copy them on demand, but this solution below is generic, easy and less chatty - although one rule: you must create (render) a clean page after postback (so
$('#submitBtn').closest('form').one('submit', function() {
var $form = $(this);
// input, textarea, select, option, ----- button, datalist, keygen, output, optgroup
$form.find('input:disabled, textarea:disabled, select:disabled, option:disabled').each(function () {
var $item = $(this);
var hiddenItem = $item.clone();
hiddenItem.removeAttr('id');
hiddenItem.removeAttr('disabled');
hiddenItem.attr('style', 'display: none');
$item.after(hiddenItem);
});
});
#readonly = true does not work on my page. I did additional research. Here is the article that explains it
ReadOnly attribute doesn't work in ASP.NET MVC Models

Resources