I have a standard Order form with a product selection. I am creating a dropdown list as per below where ProductName and ID are properties of the Product reference data model. ProductID is a property of the Order model.
The dropdown is loaded and works correctly when submitting the form.
My problem is when the user opens this form again to view his order. I load the Order model from the database and I can see that the ProductID is correctly loaded back. However, the dropdown selection remains blank. Is this standard behaviour? Perhaps I need to carry out some additional tasks. Doesn't kendo ui automatically translate the Product ID to show the Product Name in the dropdown?
#model int
#(Html.Kendo().DropDownList()
.Name("ProductID")
.OptionLabel(" ")
.DataTextField("ProductName")
.DataValueField("ID")
.DataSource(source =>
{
source.Read(read =>
{
read.Action("RefDataClientSelection_Read", "RefDataClient").Type(HttpVerbs.Post); //Set the Action and Controller name
})
.ServerFiltering(true); //If true the DataSource will not filter the data on the client.
})
)
Try using DropDownListFor() as below:
#model int
#(Html.Kendo().DropDownListFor(m => m) // or m => m.ProductId if you have a more complex model
.OptionLabel(" ")
.DataTextField("ProductName")
.DataValueField("ID")
.DataSource(source =>
{
source.Read(read =>
{
read.Action("RefDataClientSelection_Read", "RefDataClient").Type(HttpVerbs.Post); //Set the Action and Controller name
})
.ServerFiltering(true); //If true the DataSource will not filter the data on the client.
})
)
Related
I'm trying to create a form that maps to an entity of the type "Participant". A participant is in a one-to-one relationship with a 'person'. Adding a participant, I want to first give the option to choose a person already in the database and if the right one doesn't exist, create that person with the participant form.
This works if I do it with two pages/forms. The first one trying to choose an existing person, otherwise open a new page with the different form.
First page:
$form->add('person', AjaxEntityType, [ // EntityType but with select2 ajax
'class' => Person::class,
'remote_route' => 'person_ajax_list'
]);
Second page:
$participant->setPerson(new Person());
$form->add('person', PersonType::class);
// adds PersonType fields to the Participant form
Well, that works, but it's terribly slow and unecessary. What I'd rather want is having BOTH of those shown, where the PersonType form fields (first name, last name, title, company, address, etc.) are automatically populated with the persons data, if one is selected. Otherwise, if no Person is selected and the form is submitted with data entered, a new Person should be created and persisted in the database.
It's sadly not possible to render the 'person' twice, once as a dropdown and once as a PersonType form. So how would I go about achieving what I want, without surreal amounts of JavaScript?
My current solution would be to manually create all the required fields with JavaScript and populate them with the person data I'd get with another Ajax request on a onchange event on the person dropdown, then in the PRE_SUBMIT event of the form, remove the 'person' field and add it again as a PersonType field, check if the entered data corresponds to an existing person or a new one and then act accordingly. There has to be a better solution, right?
Form events have sadly otherwise proven majorly pointless, as it's not possible to attach an event listener to a 'change' event on one of the fields.
Thanks.
Ended up solving it with an unmapped person choice field and javascript to automatically update the data (using ajax).
participant/add.twig:
{% block javascripts %}
<script type="text/javascript">
$(document).ready(function () {
function onTrainerChange() {
let trainerId = $('#participant_person_choose').val();
$.get(Routing.generate('person_data_ajax', { id: trainerId }), function (data) {
$('#participant_person_gender').val(data.gender);
$('#participant_person_title').val(data.title);
$('#participant_person_firstName').val(data.firstName);
$('#participant_person_lastName').val(data.lastName);
$('#participant_person_email').val(data.email);
$('#participant_person_telephone').val(data.telephone);
if (data.company) {
let company = $('#participant_person_company');
company.empty();
company.append(new Option(data.company.text, data.company.id));
company.val(data.company.id);
company.trigger('change');
// manipulate dom directly because of .select('data') bug with select2 >=4.0
}
});
};
let trainer = $('#participant_person_choose');
trainer.change(onTrainerChange);
});
</script>
{% endblock %}
ParticipantController add:
$participant = new Participant($seminar);
$person = $participant->getPerson() ?? new Person();
$participant->setPerson($person);
$form = $this->createParticipantForm($participant)
->add('person_choose', AjaxEntityType::class, [
'mapped' => false,
'class' => Person::class,
'remote_route' => 'person_select_ajax',
'placeholder' => 'form.personCreate',
'label' => 'form.person'
])
->add('person', PersonType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
if ($form->get('reservation')->getData()) {
$participant->setInterested();
}
$personEntered = $form->get('person')->getData();
$personChosen = $form->get('person_choose')->getData();
if ($personChosen) {
$person = $personChosen;
$person->setGender($personEntered->getGender());
$person->setTitle($personEntered->getTitle());
$person->setFirstName($personEntered->getFirstName());
$person->setFirstName($personEntered->getLastName());
$person->setCompany($personEntered->getCompany());
$person->setEmail($personEntered->getEmail());
$person->setTelephone($personEntered->getTelephone());
$participant->setPerson($person);
}
$this->getDoctrine()->getManager()->persist($person);
$this->getDoctrine()->getManager()->persist($participant);
}
PersonController Ajax:
/**
* #Route("/{id}/data", name="person_data_ajax", methods={"GET"}, options={"expose": true})
*/
public function dataAjax(Person $person, PhoneNumberHelper $phonenumberHelper)
{
$arr = [
'id' => $person->id,
'gender' => $person->getGender(),
'title' => $person->getTitle(),
'firstName' => $person->getFirstName(),
'lastName' => $person->getLastName(),
'email' => $person->getEMail(),
'telephone' => $person->getTelephone() ? $phonenumberHelper->format($person->getTelephone(), PhoneNumberFormat::NATIONAL) : null,
'company' => $person->getCompany() ? [
'id' => $person->getCompany()->id,
'text' => $person->getCompany()->__toString()
] : null
];
return new JsonResponse($arr);
}
Hope this can help someone else. Really disappointed with how limited Symfonys Forms are.
Please help.
I have 3 tables
PublicationType table has columns publicationTypeID, description
Quantities table has columns quantityId, description
Agent Publicationquantities table has columns publicationTypeID, quantityId
How to write jQuery or Json in MVC3 when user select Publication dropdown list then the second dropdown list is the quantity
Dropdown list will populate based on the Publication dropdown list selected (check with the third table AgentPublicationQuantity)
Example if the user select publication id=9 Test Publication 3 then the Quantity should populate half,full, half&full for the user to select.)
From code below so far on the view page, I have two dropdown lists:
PublicationType populate Publications
Quantity populate quantities list
I wanted the Quantity to populate base on the PublicationType dropdown list value, because different publication has different available quantity.
Here is my code
public ActionResult Create(int agentID)
{
// Get data to display create page.
AgentPublicationOrder publication = new AgentPublicationOrder(); // Declare new instance of Agent Adjustment object.
AgentViewModel viewModel = new AgentViewModel(agentID, this.User.Identity.Name); // Create lightweight agent view model.
AgentPublicationOrderViewModel publicationviewmodel = new AgentPublicationOrderViewModel(agentID);
ViewBag.loggedInUserName = viewModel.loggedInUserName;
ViewBag.fullContactName = viewModel.fullContactName;
ViewBag.agentID = viewModel.agentID;
// get data to populate dropdowlist
using (var db1 = new AgentPublicationTypesDBContext())
{
var agentquantityFromDB = db1.AgentPublicationTypePublicationQuantities.Select(x => x.publicationQuantityId).ToList();
// dropdownlist pulicationType
ViewBag.AgentPublicationTypes = db1.AgentPublicationTypes.Where(x => agentquantityFromDB.Contains(x.id) && x.inactiveDate > DateTime.Today || !x.inactiveDate.HasValue).OrderBy(a => a.description).ToList();
//dropdownlist Quantity
ViewBag.Quantities = db1.PublicationQuantities.Where(x => agentquantityFromDB.Contains(x.id) || x.inactiveDate == null && x.inactiveDate > DateTime.Today).OrderBy(x => x.id).ToList();
}
return View(publication);
}
Here is my view page
<div class="three_column_row">
<div class="three_column_col">
<div class="labelCell2">
Publication:
</div>
<div class="editorCell">
#Html.DropDownListFor(model => model.agentPublicationTypeid, new SelectList(#ViewBag.AgentPublicationTypes, "id", "description", (Model.agentPublicationTypeid != 0 ? Model.agentPublicationTypeid : -1)), "--Select One--")
</div>
</div>
<div class="three_column_col">
<div class="labelCell2">
Qty:
</div>
<div class="editorCell">
#Html.DropDownListFor(model => model.quantityId, new SelectList(#ViewBag.Quantities, "id", "description"), "--Select One--")
</div>
</div>
</div>`
Problem Statement: I want to change the display name of labels(#Html.LabelFor) in Razor view of MVC based on the display names which i get from db.
I have added the dropdown list of languages in the _Layout.cshtml
<li>#Html.Action("Index", "LanguageDropdown", new { languageid = Request["languageId"] })</li>
I have created one partial view for drop down:
#model ALCMS.Web.Models.Master_or_Configuration.LanguageDropdownModel
<script type="text/javascript">
function GetLanguage() {
var languageId = $('#LanguageId').val();
var Url = "#Url.Content("~/MasterConfigGeneral/GetLanguage")";
$.ajax({
url: Url,
dataType: 'json',
data: { LanguageId: languageId },
success: function (data) {
}
});
}
</script>
<div style="display:inline-block">
#Html.DropDownListFor(l => l.LanguageID, new SelectList(Model.Languages, "Value", "Text"), "Select Language", new { id = "LanguageId" ,onchange="GetLanguage()" })
</div>
Partial View Controller:
public ActionResult Index(string languageId)
{
//return View();
var languages = dbEntity.LookupLanguages;
var model = new LanguageDropdownModel
{
LanguageID = languageId,
Languages = languages.ToList().Select(l => new SelectListItem
{
Value = Convert.ToString(l.LanguageID),
Text = l.Name
})
};
return PartialView(model);
}
In Controller Json Result method:
public JsonResult GetLanguage(int languageID)
{
JsonResult jsResult = new JsonResult();
objdbGlobalTenant.ddlLanguage = (from lsr in dbEntity.LocaleStringResources
where lsr.LanguageID == languageID
select new SelectListItem()
{
Text = lsr.ResourceValue,
Value = lsr.ResourceName
}).Distinct().ToList<SelectListItem>();
//ViewBag.Language = objdbGlobalTenant.ddlLanguage;
jsResult.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
return jsResult;
}
Now everything is working fine.I'm able to get the selected langaugeID in Json Result method in Controller based on the change event of Language dropdown. Based on this Language ID i'm getting display names(ResourceValue) which i need to apply for the particular view.
Problems:
1>After getting the display names from db how to change display names
of particular view when language change event triggers.?? For
ex:Currently i'm seeing the Create.CSHTML. Now if i change the
language dropdown it should trigger Json Event in controller and
after getting values it should apply the values on the view which it
got from db.
Note: Dropdown is in Layout.cshtml(like master in .aspx)
2>Drop-down which i placed in Layout.cshtml is getting refreshed
every time new view is loaded which inherits(layout.cshtml).How to
make the controller to retain it's state during postback??
3>How to get the selected drop-down item from the layout in multiple
Controllers,to change the display name in each view based on the langaugeid
of dropdown in layout
How to do this??If i'm doing wrong suggest me some other ways...
Below are the suggestions :
Issue 1 :
You may keep one attribute in each label which identifies them uniquely.
Your HTML should render like following
<!-- For English -->
<label label-unique-name="Name">Name</label>
<label label-unique-name="Surname">Surname</label>
<!-- For French -->
<label label-unique-name="Name">nom</label>
<label label-unique-name="Surname">nom de famille</label>
<!-- For Spanish -->
<label label-unique-name="Name">nombre</label>
<label label-unique-name="Surname">apellido</label>
Here label-unique-name is your attribute, which will remain fixed for each language. Now when you change the language from dropdown you will bring the values like below.
<!-- For English -->
<label-unique-name:"Name",label-value:"Name">;<label-unique-name:"Surname",label-value:"Surname">
<!-- For French -->
<label-unique-name:"Name",label-value:"nom">;<label-unique-name:"Surname",label-value:"nom de famille">
<!-- For English -->
<label-unique-name:"Name",label-value:"nombre">;<label-unique-name:"Surname",label-value:"apellido">
Please note : this is for understanding only, it's not a JSON.
Now using jQuery go through each label and replace the label's value. Hope it'll help you.
Issue 2 :
You can save the selected language's value in session, and generate your dropdown accordingly.
#Html.DropDownListFor(l => l.LanguageID, new SelectList(Model.Languages, "Value", "Text"), !string.isNullorEmpty(HttpContext.Current.Sessions["Language"]) ? HttpContext.Current.Sessions["Language"] : "Select Language", new { id = "LanguageId" ,onchange="GetLanguage()" })
The main issue here is validating a Kendo Grid - with an InCell edit setting.
Kendo UI grid is no more than a 'Glorified table' - it is a Html table in the end, hence my tagging of JQuery and JavaScript into this question!
This is the grid:
#(Html.Kendo().Grid<Timeshet.Web.Models.UserModel>()
.Name("Grid")
.Editable(editable => editable.Mode(GridEditMode.InCell).DisplayDeleteConfirmation("This user will now be removed from the grid. \n\n To commit this delete make sure you click Save Changes button !"))
.Sortable(sortable => sortable.AllowUnsort(false))
.ToolBar(toolbar =>
{
toolbar.Create();
toolbar.Save();
})
.Columns(columns =>
{
//columns.Bound(p => p.UserId);
columns.Bound(p => p.Forename);
columns.Bound(p => p.Surname);
columns.Bound(p => p.Email);
columns.Bound(p => p.Txtname);
columns.Bound(p => p.Mobile);
columns.Bound(p => p.HolidayEntitlement);
columns.Bound(p => p.Password);
columns.Bound(p => p.Level);
columns.Bound(p => p.Active).ClientTemplate("<input type='checkbox' class='chkboxActive' #= Active ? checked='checked' : '' # ></input>");
columns.Bound(p => p.UserAccess);
columns.Command(command => command.Destroy()).Width(100).Visible(User.IsInRole(Constants.Admin)).Hidden();
})
// .Events(events => events.SaveChanges("validateInputOnSaveChanges"))
.DataSource(dataSource => dataSource.Ajax()
.Model(model => model.Id(p => p.UserId))
.Batch(true)
//.Events(events=>events.Change("validateInputOnSaveChanges"))
.Events(events => events.Error("error"))
// .Events(events => events.RequestStart("requestStart"))
.Events(events => events.RequestEnd("onRequestEnd"))
.Create(update => update.Action("UserCreate", "User"))
.Read(read => read.Action("UserRead", "User").Data("ExtraData"))
.Update(update => update.Action("UserUpdate", "User"))
.Destroy(update => update.Action("UserDelete", "User"))
)
)
As you see, it has inCell edit mode, whose validation is proving difficult.
I have tried to Parse the grid and look for the k-dirty-class which gets enabled on an edited cell like this. I was doing this on saveChanges event of the grid, which gets fired when the save changes button is clicked:
$("#Grid tbody").find('td').each(
function () {
debugger;
// run for specific columns - where validation is needed
// var isDirty = cellToValidate.hasClass('k-dirty-cell');
var isDirty = $(this).hasClass('k-dirty-cell');
if (isDirty == true) {
var cellContent = $(this).context.innerText;
var cellIndex = $(this).context.cellIndex;
alert(cellContent + cellIndex);
}
});
The problem I am trying to solve is that when a User creates a new user (row) and enters the Forename and Surname and save - the grid doesn't validate the TxtName column, because it is set to InCell edit mode where only clicked cells get validated as per the view-model.
This has to be done in the InCell edit mode. Inline Editing works, but it is not the requirement here.
My plan is to validate the input on dirty cells but this is also is proving difficult, because not all dirty cells need validating but only the TextName column!
I wonder if there is anyway I could capture the details of the new row being sent to the controller, which is basically the view-model?
Many thanks.
I would write a validation method for the saveChanges event that loops through the grid rows
You could loop through the rows like so:
var currentRows = grid.tbody.find("tr");
Once you have your rows, you'll need to grab each dataItem ( grid.dataItem(currentRows[i]) ) and then check a property that you can be certain that an inserted row wont yet have assigned.
For our particular model we used a property called model.ticketID because the ticket ID was only created after a DB insert.
From here, you can set up your own validation for the row, or you can flip on editable for the row, and use the kendo recommended approach for validation.
For those who may be having/ or may have this issue; this is how I ended up solving it:
I used the grid's saveChanges event to find dirty cells, then from there get to the parent row, then from there navigate to the cell that needs to be validated; get its text and do the validation - in my case I only wanted to validated if the input value is not null:
//On Kendo UI grid:
.Events(events => events.SaveChanges("validateInputOnSaveChanges"))
// The JavaScript function:
function validateInputOnSaveChanges(e) {
//Validate TxtName field
var columnIndex = 3; // Index of the column to validate
$("#Grid tr td").each(function () {
var dirty = $(this).hasClass('k-dirty-cell');
if (dirty == true) {
var TxtName = $(this).parent().children()[columnIndex].innerText; // Get the text input in this field
if (TxtName === "") { // validate
e.preventDefault(true); // halt the Create function of DataSource
alert("Txt Name Cannot be Blank.");
return false; // quit the loop
}
}
return true;
});
}
Kind regards,
t_plusplus
I have a requirement of a search page in which I am using KendoUI grid to display the search result.
I have a textbox and button and if text is entered and on click event of button I hace to display the grid with the list of users matching to search result.
I am using ASP.net MVC and KENDOUI grid.
My View:
The search box and button:
<div id="SearchSection">
<input type="text" id="txtSearch" class="k-textbox"/>
<button class="k-button"id="btnSearch" style="width:150px">Search</button>
</div>
The KendoUI grid
<div id="ADUserSection">
<div id="ADSearchedUser">
List of users in Active directory:
<div id="ADuserGrid">
#(Html.Kendo().Grid<ADUser>()
.Name("kADUser")
.Columns(columns =>
{
columns.Bound(p => p.UserLoginName);
columns.Bound(p => p.UserDisplayName);
})
.AutoBind(false)
.DataSource(ds =>
{
ds.Ajax()
.Read(read =>
{
read.Action("GetADUser", "ManageUsers")
.Data("AdditionalData");
});
})
)
)
</div>
</div>
My JavaScript Function:
<script>
$(document).ready(function () {
$("#ADUserSection").fadeOut(0);
$("#AvailableUserRoleSection").fadeIn()
});
var enterTest
$("#btnSearch").click(function () {
debugger;
enterTest = $("#txtSearch").val().trim();
if (enterTest == "") {
$("#ADUserSection").fadeOut();
}
else {
AdditionalData();
$("#ADUserSection").fadeIn();
var grid = $("kADUser").data("kendoGrid").dataSource.read({ searchText: enterTest });
//**Breaks at this Point**//
}
});
function AdditionalData() {
//$("#ADuserGrid").empty();
$("#ADuserGrid").fadeIn();
return {
searchText: enterTest
}
}
My Controller Action
public JsonResult GetADUser([DataSourceRequest] DataSourceRequest request, string searchText)
{
viewmodel.searchedADUser = model.GetUserFromAD(searchText);
return Json(viewmodel.searchedADUser.ToList().ToDataSourceResult(request), JsonRequestBehavior.AllowGet);
}
On the button click event in javascript when I attach the grid to event I get the error the datasource read is not recognised.
Exact error is:
JavaScript runtime error: Unable to get property 'dataSource' of undefined or null reference
Please help me in that. any idea please share or if I am doing anything wrong in my above code please point out.
I am very new to KendoUi and MVC so please elaborate n yur explanation.
I got the above problem becosue of missing # before the grid name.
But Now I habe one more issue, even though I am follwing all the proper step.
In my above AdditionalData javascript function my parameter is not getting set set in the paaremeter
function AdditionalData() {
//$("#ADuserGrid").empty();
$("#ADuserGrid").fadeIn();
return {
searchText: enterTest
}
}
This searchText is not getting set even tough I am getting value in enterTest.
Any help will be of very great use. I am really stuck in this.
You're trying to access your grid with:
var grid = $("kADUser").data("kendoGrid");
$("kADUser") won't find any elements, because it's looking for a kADUser tag, and the .data() of an empty jQuery set is null.
As a result, when you try to access grid.dataSource, grid is "undefined or null" (which is what the error is telling you).
You should be using an id selector:
var grid = $("#kADUser").data("kendoGrid");
In general, I'd suggest to avoid compound statements and keep it at one statement per line. This will make debugging much easier.