Cascading DropDownListView not calling read.action? - asp.net-mvc

I'm using Visual Studio 2012 Internet Application that I've enabled for Kendo UI. This is a MVC4 C# and Razor View Project.
I have more then 6 models i'm eventually going to cascade with these dropdowns
I have been following The Tutorial step by step ( actually copied it and renamed in code ).
When page loads the UI looks great, but NO data is bound to the DropdownLists(/comboboxes)
I'm really only focused on the first DropDownList atm wich is
<p>
<label for="clients">Clients:</label>
#(Html.Kendo().DropDownList()
.Name("clients")
.HtmlAttributes(new { style = "width:300px" })
.OptionLabel("Select Client...")
.DataTextField("Client")
.DataValueField("ClientID")
.DataSource(source => {
source.Read(read => {
read.Action("GetCascadeClients", "ComboBox");
});
})
)
</p>
when the code reaches
.DataSource(source => {
source.Read(read => {
read.Action("GetCascadeClients", "ComboBox");
});
})
it's supposed to call this action, but does not this action is located in the controller for this view
public JsonResult GetCascadeClients()
{
var Clients = db.Clients.AsQueryable();
return Json(db.Clients.Select(c => new { ClientID = c.ClientID, Client = c.Client }), JsonRequestBehavior.AllowGet);
}
My question is what am I doing wrong, it almost has to be something stupid.... ( Yes data is in the database, yes in other controls they bind fine.)
EDIT: Thought it was a little peculiar that the 2 dropdownboxes below show text and the top one doesnt?
Breakpoints not being hit here:
Also i have this scripttag that runs, possibly could be something wrong with it Keep in mind im only looking to fill the first ( if first works the rest should fall in )
<script>
$(document).ready(function () {
var clients = $("#clients").data("kendoDropDownList"),
countys = $("#countys").data("kendoDropDownList"),
townShips = $("#townShips").data("kendoDropDownList");
$("#get").click(function () {
var clientsInfo = "\nclients: { id: " + clients.value() + ", name: " + clients.text() + " }",
countysInfo = "\ncountys: { id: " + countys.value() + ", name: " + countys.text() + " }",
townShipsInfo = "\ntownShips: { id: " + townShips.value() + ", name: " + townShips.text() + " }";
alert("Select Tract To Upload:\n" + clientsInfo + countysInfo + townShipsInfo);
});
});
</script>

#Don Thomas Boyle,I was able to copy your code and use my controller to return json data and I get the Option Label to show "Select Client...". Are you able to get the json string returned by manually calling it in the browser address bar? What is the name of your Controller? "Combobox" sounds like a suspicious controller name to me.
<p>
<label for="clients">Clients:</label>
#(Html.Kendo().DropDownList()
.Name("clients")
.HtmlAttributes(new { style = "width:300px" })
.OptionLabel("Select Client...")
.DataTextField("SiteName")
.DataValueField("ID")
.DataSource(source => {
source.Read(read => {
read.Action("GetSites", "PlayGround");
});
})
)
Here is my controller:
namespace MyWebApp.Controllers
{
public class PlayGroundController : Controller
{
readonly MyEntities context = new MyEntities();
public JsonResult GetSites()
{
var sites = context.vSites.Select(s => new SitesVM
{
ID = s.ID,
SiteName = s.SiteName
}).OrderBy(s => s.SiteName);
return Json(sites, JsonRequestBehavior.AllowGet);
}
}

this line :
.DataTextField("Client")
should be:
.DataTextField("ClientName")

Related

Telerik Client Template Conditions

I am using Telerik MVC Grid control to show a data grid. The detail of my grid is calling the following Client Detail template:
<script id="client-template" type="text/x-kendo-template"> <%: Html.Kendo().Grid<ASML_Scheduler.ScheduleService.AgentViewData>()
.Name("grid_#=WorkgroupName#")
.DataSource(dataSource =>
dataSource.Ajax().Read(read => read.Action("Agents_Read", "Home", new {workgroupname= "#=WorkgroupName#", name = ViewData["LoggedInUser"] }))
)
.Columns(columns =>
{
columns.Bound(product => product.AgentName).ClientTemplate("<strong>\\#:AgentName\\#</strong>");
//columns.Bound(product => product.IsLoggedOn);
//columns.Bound(product => product.IsLoggedOn).ClientTemplate("<div class='mystyle'>\\#:IsLoggedOn\\#</div>");
columns.Bound(product => product.IsLoggedOn).ClientTemplate(
"# if (IsLoggedOn != false) { #" +
"<div class='mystyle'>\\#:IsLoggedOn\\#</div>" +
"# } else { #" +
"<div>\\#:IsLoggedOn\\#</div>" +
"# } #"
);
columns.Bound(product => product.IsScheduled);
})
.ToClientTemplate()
%>
</script>
The problem I have is with the IsLoggedOn client template as it does not recognise the IsLoggedOn != false.
Can anyone see what I havedone wrong here.
personally with this sort of thing I prefer doing this.
change this:
columns.Bound(product => product.IsLoggedOn).ClientTemplate(
"# if (IsLoggedOn != false) { #" +
"<div class='mystyle'>\\#:IsLoggedOn\\#</div>" +
"# } else { #" +
"<div>\\#:IsLoggedOn\\#</div>" +
"# } #"
);
to
columns.Bound(product => product.IsLoggedOn)
.ClientTemplate("#=StyleLogin(data.IsLoggedOn)#");
then create a javascript function
function StyleLogin(IsLoggedOn)
{
var value = '';
if (IsLoggedOn != false) {
value = '<div class="mystyle">' + IsLoggedOn + '</div>';
} else {
value = '<div>' + IsLoggedOn + '</div>';
}
return value;
}
This way you can easily debug the code and also reuse the function elsewhere if needed.

Can't get extra form fields when the form is submitted

My automatic generated base form class is as follows:
abstract class BaseGestorForm extends BaseFormDoctrine {
public function setup() {
$this->setWidgets(array(
'persona_fk' => new sfWidgetFormInputHidden(),
'unitat_fk' => new sfWidgetFormInputHidden(),
'baixa' => new sfWidgetFormDateTime(),
));
$this->setValidators(array(
'persona_fk' => new sfValidatorChoice(array('choices' => array($this->getObject()->get('persona_fk')), 'empty_value' => $this->getObject()->get('persona_fk'), 'required' => false)),
'unitat_fk' => new sfValidatorChoice(array('choices' => array($this->getObject()->get('unitat_fk')), 'empty_value' => $this->getObject()->get('unitat_fk'), 'required' => false)),
'baixa' => new sfValidatorDateTime(array('required' => false)),
));
$this->widgetSchema->setNameFormat('gestor[%s]');
$this->errorSchema = new sfValidatorErrorSchema($this->validatorSchema);
$this->setupInheritance();
parent::setup();
}
public function getModelName() {
return 'Gestor';
}
}
In the form I added two extra fields (totes_unitats and unitats_a_gestionar). The first field is a drop down list where users select one or more choices and using jquery when a user press a button the options selected are added to unitats_a_gestionar drop down list. At the same time, these options are removed from totes_unitats list.
class GestorForm extends BaseGestorForm {
public function configure() {
unset($this['baixa']);
$this->widgetSchema['persona_fk'] = new sfWidgetFormChoice(array(
'choices' => UsuariLdap::getAllUsuaris()
));
$this->widgetSchema['totes_unitats'] = new sfWidgetFormChoice(array(
'choices' => UnitatTable::findAllUnitatsPerOrdreArray(),
'multiple' => true
));
$this->widgetSchema['unitats_a_gestionar'] = new sfWidgetFormChoice(array(
'choices' => array(),
'multiple' => true
));
$this->widgetSchema->setLabels(array(
'persona_fk' => 'Gestor',
'unitat_fk' => 'Unitat',
'totes_unitats' => 'Totes les unitats',
'unitats_a_gestionar' => 'Unitats a gestionar'
));
$this->validatorSchema->setOption('allow_extra_fields', true);
$this->validatorSchema['persona_fk'] = new sfValidatorString(array('required' => true), array('required' => 'Requerit'));
}
}
Where I find the problem is in the actions file. First of all, I call the executeNouGestor method that renders the form. Then when the user press to proceed and create the Gestor object, it calls executeValidaGestor that validates the form. This last method calls processFormGestor where there is no way to retrieve the unitats_a_gestionar extra field.
public function executeNouGestor(sfWebRequest $request) {
$this->gestorForm = new GestorForm();
}
public function executeValidaGestor(sfWebRequest $request) {
$this->forward404Unless($request->isMethod(sfRequest::POST));
$this->gestorForm = new GestorForm();
$this->processFormGestor($request, $this->gestorForm);
$this->setTemplate('nouGestor');
}
protected function processFormGestor(sfWebRequest $request, sfForm $gestorForm) {
$gestorForm->bind($request->getParameter($gestorForm->getName()), $request->getFiles($gestorForm->getName()));
if ($gestorForm->isValid()) {
var_dump($_POST);
var_dump($request->getParameterHolder()->getAll());
...
}
}
These two var_dump shows me the following information:
var_dump($_POST):
array(2) {
["gestor"]=>
array(2) {
["persona_fk"]=>
string(3) "330"
["_csrf_token"]=>
string(32) "91e18aa0570bfc7558d21ebb4b98f512"
}
["Desar"]=>
string(5) "Desar"
}
var_dump($request->getParameterHolder()->getAll()):
array(4) {
["gestor"]=>
array(2) {
["persona_fk"]=>
string(3) "330"
["_csrf_token"]=>
string(32) "91e18aa0570bfc7558d21ebb4b98f512"
}
["Desar"]=>
string(5) "Desar"
["module"]=>
string(13) "administracio"
["action"]=>
string(12) "validaGestor"
}
So, as you can see, in ["gestor"] there is no track neither totes_unitats nor unitats_a_gestionar extra form fields. I have no idea why. The way I show the form fields in the template is as usual:
<?php echo $gestorForm['persona_fk']->renderLabel(); ?>
<div class="input"><?php echo $gestorForm['persona_fk']->render(); ?></div>
<div class="error-input"><?php echo $gestorForm['persona_fk']->renderError(); ?></div>
<?php echo $gestorForm['totes_unitats']->renderLabel(); ?>
<div class="input multiple"><?php echo $gestorForm['totes_unitats']->render(); ?></div>
<div class="error-input"><?php echo $gestorForm['totes_unitats']->renderError(); ?></div>
<?php echo $gestorForm['unitats_a_gestionar']->renderLabel(); ?>
<div class="input multiple"><?php echo $gestorForm['unitats_a_gestionar']->render(); ?></div>
<div class="error-input"><?php echo $gestorForm['unitats_a_gestionar']->renderError(); ?></div>
I also add the jquery code that manage the options added or removed between the two drop down lists with multiple selection:
function afegirTreureUnitats() {
var boto_afegir = $("#btn-multiple-afegir");
var boto_treure = $("#btn-multiple-treure");
boto_afegir.click(function() {
var selectedItems = $("#gestor_totes_unitats option:selected");
var output = [];
$.each(selectedItems, function(key, e)
{
output.push('<option value="' + e.value + '">' + e.text + '</option>');
});
$("#gestor_unitats_a_gestionar").append(output.join(""));
ordenaOptionsSelect("gestor_unitats_a_gestionar");
selectedItems.remove();
});
boto_treure.click(function() {
var selectedItems = $("#gestor_unitats_a_gestionar option:selected");
var output = [];
$.each(selectedItems, function(key, e)
{
output.push('<option value="' + e.value + '">' + e.text + '</option>');
});
$("#gestor_totes_unitats").append(output.join(""));
ordenaOptionsSelect("gestor_totes_unitats");
selectedItems.remove();
});
}
function ordenaOptionsSelect(idSelect)
{
var options = $('#' + idSelect + ' option');
options.sort(function(a, b)
{
if (a.text > b.text)
return 1;
else if (a.text < b.text)
return -1;
else
return 0;
});
$('#' + idSelect).empty().append(options);
}
$(document).ready(function() {
afegirTreureUnitats();
});
The form rendered has this appearance:
https://drive.google.com/file/d/0B0Mz720p9Q_DN1RnYWIyR0pXOTQ/edit?usp=sharing
I have also found a curious fact. If I select one of the options in the drop down list, either totes_unitats or unitats_a_gestionar they are sent through POST method, but only one (if I select more than one I only can get one of the options selected).
When you use <select> elements on the form, or <input> of type radio or checkbox the browser will send their values on form submission only when the fields have any options selected.
The list of options in the <select> tag is not sent back to the server. Only the values of the options which are actually selected.
You can resolve your problem in two ways:
Either create a JS which will modify your form just before sending it and will select all the items on both your lists. This way your form will send the values and you will be able to work with them on the server side.
Other option is to add two hidden fields which will keep the lists of the options and modify these lists together with the <select> fields.

Kendo UI Grid - How to save current radio button state

I am currently able to submit all records on my Kendo Grid back to the controller, but it does not reflect the latest state of the radio button. I dont want to have to click on a cell multiple times, to go into edit mode, nor use an edit button. I want to simply be able to make a radio button selection, click save and have the current state be reflected on my controller.
Razor View
#model IEnumerable<ECM.DAL.ViewModels.Roles.AcctAppUserRoles>
#using ECM.DAL.Infrastructure.Managers
#using GridEditMode = Kendo.Mvc.UI.GridEditMode
#{
ViewBag.applicationType = (int)SystemWideConfiguration.ApplicationTypes.ECM;
ViewBag.acctId = RightsManager.AccountId;
}
#(Html.Kendo().Grid(Model)
.Name("EcmRolesGrid")
.Columns(columns =>
{
columns.Bound(x => x.IsActive).Width(46)
.ClientTemplate("<input type='radio' name='isActive' value='#= IsActive #' # if (IsActive) { # checked='checked' # } # />")
.Title("Select Role")
.HtmlAttributes(new {style = "text-align:center"});
columns.Bound(r => r.RoleName).Width(75);
columns.Bound(r => r.RoleDescription).Width(125);
})
.HtmlAttributes(new { style = "height:340px;" })
.Editable(editable => editable.Mode(GridEditMode.InLine))
.DataSource(dataSource => dataSource
.Ajax()
.ServerOperation(false)
.Model(model => model.Id(p => p.UserId))
.Read(read => read.Action("GetApplicationAndAccountRoles", "User", new { applicationType = ViewBag.applicationType, acctId = ViewBag.acctId, userId = ViewBag.EcmRoleUserId.ToString() }))
.Update(update => update.Action("SaveApplicationRoles", "User")))
)
Controller:
[AcceptVerbs(HttpVerbs.Post)]
[HandleAjaxReturnableException]
public void SaveApplicationRoles(IEnumerable<AcctAppUserRoles> updatedRoles)
{
var userRoleDal = new UserRoleDal();
var roleDal = new RoleDal();
var applicationId = Guid.Empty;
var userId = Guid.Empty;
if (updatedRoles != null)
...
Javascript (I am using this because I have several tabs in this view with several grids)
function EcmRolesGridHasChanges() {
$.ajax({
url: 'user/SaveApplicationRoles',
cache: false,
type: 'POST',
contentType: 'application/json;',
charset:'utf-8',
data: JSON.stringify($("#EcmRolesGrid").data().kendoGrid._data)
});
}
Let me give you a visual as well....
When the grid is initially loaded the "Order Entry" Role is selected.
(Not showed)
I'll now choose "Limited User"
When I click save this is what I get on the controller:
I was expecting the first one to be false, second true and third false.
Any ideas?
Thank you.
You need to set the model on radio button click to let the grid know that particular row has been set as dirty therefore fire update event with updated model values
so add this on radio button click..
***************************Grid*******************
columns.Bound(x => x.IsActive).Width(46)
.ClientTemplate("<input type='radio' name='isActive' value='#= IsActive #' # if (IsActive) { # checked='checked' # } # onclick='radioBoxClick(this)' />")
**********************Script********************
//checkbox click function
function radioBoxClick(e) {
grid = $("kendoGrid").data().kendoGrid;
var dataItem = grid.dataItem($(e).closest('tr'));
var model = grid.dataSource.get(dataItem.UserId);
model.set("isActive", e.checked ? 1 : 0);
}
Minor modification to the answer that Shaz and Jayesh Goyani provided.
The function below goes over the other radio buttons and sets it to false.
function radioBoxClick(e) {
var grid = $("#EcmRolesGrid").data().kendoGrid;
var elementCount = grid.dataSource._data.length;
var dataItem = grid.dataItem($(e).closest('tr'));
var model = grid.dataSource.get(dataItem.RoleId);
model.set("IsActive", e.checked ? 1 : 0);
for (var i = 0; i < elementCount; i++) {
var elem = grid.dataSource._data[i];
if (elem.RoleId != model.RoleId)
elem.set("IsActive", 0);
}
}

Kendo Upload in Kendo grid rows

I am using Kendo() grid in my application which has binding with an model.
I want to provide Upload control in Grid against each row. Please see razor view design as follows
#(Html.Kendo().Grid<Model>()
.Name("Grid")
.Columns(col =>
{
col.Template(#<text></text>).ClientTemplate("<a Title='Export' href='" + Url.Action("Export", "RouteFileExport", new { Id = "#= RouteScheduleID #", routeID = "#= RouteID #" }) + "'><img src=" + #Url.Content("~/Content/images/download.png") + "></a>").Title("Export");
col.Template(#<text>#(Html.Kendo().Upload()
.Name("attachments<#= ID #>")
.HtmlAttributes(new { id = "attachments<#= ID #>" })
.Multiple(false)
.Async(async => async
.Save("Save", "Controller", new { folder = "<#= ID #>" })
.AutoUpload(true)
)
)</text>).Title("Import");
col.Command(command =>
{
command.Destroy();
command.Custom("Unlock");
command.Custom("Notification");
}
);
})
With above design i am not able to get the upload control displayed inside grid. Its displaying BLANK column.
Please let me know how can i achieve upload against each kendo grid row.
Thanks
Are you looking for a custom button in the last column? If you use the custom command buttons it can be linked to JQuery or a controller action like below:
columns.Command(cmd => cmd.Custom("Upload").Text("Upload").Click("UploadJqueryScript")).Width(75);
columns.Command(cmd => cmd.Custom("Upload").Action("UploadMethod", "Controller")).Width(75);
Have you tried these options?

Telerik mvc grid tab order issue

I am working in an MVC 3.0 application. In my project I used Telerk mvc grid for data listing. I made grid edit model as "InCell" and provided key board navigation in my question answer area. Each question will have 2 answer options such as "Facts" and "Actions" and will be numeric value. I have used "integer" editor template for this purpose. My requirement is that when the user presses tab key from "Facts" integer textbook, focus will move it to "Actions" integer textbox and if the user presses tab from "Actions" it will move to next row "Facts" text box. But currently key board navigation goes through all cells in the grid. There are few columns between "Facts" and "Actions". My code for grid listing looks like.
#(Html.Telerik().Grid<AnswerQuestionVM>()
.Name("GridQuestions")
.DataKeys(keys =>
{
keys.Add(p => p.QuestionID);
})
.Columns(columns =>
{
columns.Bound(p => p.QuestionNumber).Format("{0:0.00}").HtmlAttributes(new { style = "text-align:center;" }).Title("#").Width("5%").ReadOnly();
columns.Bound(p => p.QuestionName).Title("Question Name").Width("43%").ReadOnly();
columns.Bound(p => p.Facts).Width("8%");
columns.Template(#<text></text>).ClientTemplate("<img src='" + #Url.Content("~/images/help.gif") + "' name='help' alt='help' title='<#=FactOptions#>' />");
columns.Bound(p => p.Actions).Width("8%");
columns.Template(#<text></text>).Width("2%").ClientTemplate("<img src='" + #Url.Content("~/images/help.gif") + "' name='help' alt='help' title='<#=ActionOptions#>' />");
columns.Template(#<text></text>).Title("Skip").Width("3%").ClientTemplate(
"<# if(Skip==false) {#>" +
"<input type='checkbox' style='cursor:pointer;' class='skipClass' />" +
"<#} else{#>" +
"<input type='checkbox' style='cursor:pointer;' class='skipClass' checked='checked' />" +
"<# } #>"
);
columns.Bound(p => p.Note).Title("Note").Width("26%");
})
.Editable(editing => editing.Mode(Telerik.Web.Mvc.UI.GridEditMode.InCell))
.KeyboardNavigation( navigation => navigation.EditOnTab(true))
.ClientEvents(e => e.OnSave("OnSave"))
.DataBinding(dataBinding =>
{
dataBinding.Ajax().Select("GetQuestion", "AnswerQuestion", new { Area = "question", ajax = true }).Enabled(true);
})
.Scrollable(scrolling => scrolling.Enabled(false))
.Sortable(sorting => sorting.Enabled(true))
.Pageable(paging => paging.Enabled(true))
.Filterable(filtering => filtering.Enabled(true))
.Groupable(grouping => grouping.Enabled(false))
.Footer(true)
)
Code for Integer editor template for "Facts" & "Actions" columns bellow.
#(Html.Telerik().IntegerTextBox()
.Name(ViewData.TemplateInfo.GetFullHtmlFieldName(string.Empty))
.InputHtmlAttributes(new { style = "width:100%", pattern = "[0-9]*" })
.MinValue(1)
.MaxValue(5)
.Value(Model)
)
Please provide a solution. Any help is appreciated.
Here is what I can suggest you as a work-around because your goal is not supported out of the box.
Feel free to optimize/change the implementation or to make it more generic (e.g. use classes to find cells and not to rely on indexes)
$(function () {
$('#persons tbody').on('keydown', function (e) {
if (e.keyCode == 9) {
var currentCell = $(e.target).closest('td');
var cellIndex = currentCell.index();
if (cellIndex == 2 || cellIndex == 4) { //if editing cell in third or fifth column, use different indexes if needed
e.stopPropagation();
e.preventDefault();
var grid = $('#persons').data().kendoGrid;
if (cellIndex == 2) {
var cellToEdit = currentCell.parent().find('td:eq(4)');
grid._handleEditing(currentCell, cellToEdit);
}
if (cellIndex == 4) {
var cellToEdit = currentCell.parent().find('td:eq(2)');
grid._handleEditing(currentCell, cellToEdit);
}
setTimeout(function () {
cellToEdit.find('input').focus();
})
}
}
})
})
I´m not really sure how to do this, but have you tried using something like tabindex, perhaps by using it within the htmlAttributes? Anyway, I have never done anything like this but maybe you can try something in that area:
columns.Bound(p => p.Facts).Width("8%").HtmlAttributes(new { tabindex = 1 });
columns.Bound(p => p.Actions).Title("Practice").Width("8%").HtmlAttributes(new { tabindex = 2 });
Since you are using Telerik Grid, you might have to mix this somehow within each item. Then again, maybe I´m misunderstanding your point (I´ve been known to do that) :)

Resources