Pass argument using Client Side in Telerik MVC - javascript

I'm developing some application using Telerik MVC.I wanted to pass Argument from client side.Is there any way to do it?
Here is my code for rad window
#{ Html.Telerik().Window()
.Name("NewsWindow")
.Title("Edit Here")
.Draggable(true)
.Scrollable(true)
.Resizable(resizing => resizing
.Enabled(true))
.LoadContentFrom("News/NewsEditor")
.Modal(true)
.Buttons(b => b.Refresh().Close())
.Width(600)
.Height(650)
.Visible(false)
.Render();
}

Remove
.LoadContentFrom("News/NewsEditor")
Add a function containing below codes and bind it to your desired event.
$("#NewsWindow")
.data("kendoWindow")
.refresh({
url: baseURL + "News/NewsEditor",
data: { argumentName: argumentValue }
})
.open();

Related

How to use DevExtreme in partial view (ASP.NET MVC)?

I try to use DevExtreme component in partial view.
But my partial view page shown when I click on the element.
And in the main page after the click I have error
Newtonsoft.Json.JsonSerializationException: Self referencing loop detected for property 'ApplicationEntity' with type 'System.Data.Entity.DynamicProxies.ApplicationEntity_50A6A66F1464C1DE4E8A736E85D88C5AF4F4249EAE26FB21C4F82592E001885D'. Path 'data[0].ApplicationEntity.ApplicationEntityHistories[0]'.
browser console screen
Main page Code:
<div class="row">
<div class="col-md-7">
<button id="btn">CLICK</button
</div>
<div class="col-md-5" id="divPartialViewContainer">
</div>
</div>
<script>
$(document).ready(function () {
$("#btn").on("click", function () {
var text = $(this).text().trim();
if (text.length > 0) {
console.log(text);
$.ajax({
url: '/RiskMap/RiskDetailsPartial/',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify({ 'param': text }),
success: function (content) {
$('#divPartialViewContainer').html(content);
},
error: function (e)
{
console.log(e);
}
});
}
});
});
</script>
Controller Code
[HttpPost]
public async Task<ActionResult> RiskDetailsPartial(string param)
{
return PartialView("_RiskDetails", new List<Risk>());
}
Partial View code:
#model IEnumerable<Core.Models.Risk>
#using Core.Models
#using Core.ComplexTypes
#{
ViewBag.Title = "Risks";
}
<h2>Risks</h2>
#(Html.DevExtreme().DataGrid<Risk>()
.DataSource(Model)
.Columns(columns =>
{
columns.AddFor(m => m.Id);
columns.AddFor(m => m.Impact);
columns.AddFor(m => m.Probability);
})
)
The message is clear you just need to read it more thoroughly.
Newtonsoft.Json.JsonSerializationException: Self referencing loop
detected for property 'ApplicationEntity' with type
'System.Data.Entity.DynamicProxies.ApplicationEntity_50A6A66F1464C1DE4E8A736E85D88C5AF4F4249EAE26FB21C4F82592E001885D'.
Path 'data[0].ApplicationEntity.ApplicationEntityHistories[0]'.
Json serializer is attempting to serialize some kind of entity(lets call it EntityA) you passed to it, but the problem is that this entity contains another entity(lets call it EntityB) that contains the first entity(EntityA). This is going in circles!
This has also happened to me with my own ORM and I found out the problem is lazy loading. I solved it by adding an interface to each of my entities:
interface IJSonify
{
object Json();
}
Here I simply return an anonymous object. Entity that implements this interface decides how it will represent itself as JSON object.
I had the same problem and I solved it by declaring JsonConvert defaultSettings on webApplication init.
JsonConvert.DefaultSettings = () => new JsonSerializerSettings
{
Formatting = Newtonsoft.Json.Formatting.Indented,
ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
};
Apparently DevExtreme don't use standard ASP.NET MVC json serializer inside DataSourceLoader.Load(..) method, so if you set ASP.NET MVC json serializer ReferenceLoopHandling setting it is not enough.
Another solution is use [JsonIgnore] dataAnnotation above the property that generate the loop reference

Getting kendo-window parameter

I have a JavaScript method that opens up a kendo-window, this window contains a kendo-grid which has a datasource that I want to get from my controller. In order to get the data to fill this grid I need to pass on an ID. The JavaScript method that opens up this window contains the necessary data, however I do not know how to get this data in my kendo-grid. I need to get my ID to the (read => read.Action("Read_Action", "ControlerName", new { linenum = ??? }) part where I want to replace the question marks with my ID.
JavaScript:
function showDetails(e) {
e.preventDefault();
var dataItem = this.dataItem($(e.currentTarget).closest("tr"));
console.log(dataItem.LineNum);
var wnd = $("#Details").data("kendoWindow");
wnd.center().open();
}
Kendo-window:
#{Html.Kendo().Window().Name("Details")
.Title("Location Details")
.Visible(false)
.Modal(true)
.Draggable(true)
.Width(800)
.Height(600)
.Content(
Html.Kendo().Grid<TelerikMvcApp1.Models.BinLocationItemModel>()
.Name("LocItemGrid")
.DataSource(dataSource => dataSource
.Ajax()
.Model(model => model.Id(m => m.BinLocationItemId))
.Read(read => read.Action("Read_Action", "ControlerName", new { linenum = ??? })))
.ToHtmlString()).Render();
}
You can only do this using a controller to open your window content as a partial view.
Set up your controller which will render the partial view and add the id to ViewBag to retrieve in kendo window,
public ActionResult GetKendoWindow(){
ViewBag.Id = 123;
return PartialView("_PartialView"); // Html file name
}
Your "_PartialView" file will now contain the grid only with Id assigned from ViewBag.Id
Html.Kendo().Grid<TelerikMvcApp1.Models.BinLocationItemModel>()
.Name("LocItemGrid")
.DataSource(dataSource => dataSource
.Ajax()
.Model(model => model.Id(m => m.BinLocationItemId))
.Read(read => read.Action("Read_Action", "ControlerName", new { linenum = ViewBag.Id }))
Your kendo().window() method will change to this (without the content as it'll load from the Partial View)
#{Html.Kendo().Window().Name("Details")
.Title("Location Details")
.Visible(false)
.Modal(true)
.Draggable(true)
.Width(800)
.Height(600)
.LoadContentFrom("GetKendoWindow", "Controller")
.ToHtmlString()).Render();
}
If your ID is coming from the parent page (the page you're opening the window from), you will need to pass the ID up to the controller, your .LoadContentFrom("GetKendoWindow", "Controller") would then become .LoadContentFrom("GetKendoWindow?ID=123", "Controller").
And your controller declaration would become public ActionResult GetKendoWindow(int ID)
Edit:
As you retrieve the value from JavaScript event, you would preferably want to open your window using JavaScript for simplicity, in your event put the following
$("#Details").kendoWindow({
width: "620px",
height: "620px",
title: "Window Title",
content: {
url: "GetKendoWindow",
type: "GET",
data: {ID : dataItem.ID}
}
});
Remove your Kendo().Window() Razor function completely, and leave an empty div with id Details, and open the window using $("#Details").data("kendoWindow").center().open()
Complete code for simplicity:
<div id="Details"></div>
<script>
// Your event function where you retrieve the dataItem
$("#Details").kendoWindow({
width: "620px",
height: "620px",
title: "Window Title",
content: {
url: "GetKendoWindow",
type: "GET",
data: {ID : dataItem.ID}
}
});
$("#Details").data("kendoWindow").center().open()
//End the event function
</script>
Then add your controller method from above.
public ActionResult GetKendoWindow(int ID){
ViewBag.Id = ID;
return PartialView("_PartialView"); // Html file name
}
You could use Kendo DataSource additional data like this:
$("#grid").data("kendo-grid").dataSource.read({additional:"data"});
This is working on grid demo page: http://demos.telerik.com/kendo-ui/grid/remote-data-binding. It adds param to the request.
You could probably set the function returning additional data in dataSource - see the docs: http://docs.telerik.com/aspnet-mvc/helpers/grid/faq#how-do-i-send-values-to-my-action-method-when-binding-the-grid?
EDIT 1
You can achieve this simply by setting the grid's additional request data:
$("#grid").data("kendo-grid").dataSource.transport.options.read.data = { additional: "data"};
So you open the window with kendo grid. Select the grid with typical $(...).data("kendoGrid"). An then set the dataSource.transport.options.read.data to your line id.

How do I populate a list field in a model from javascript?

I have a Kendo.MVC project. The view has a model with a field of type List<>. I want to populate the List from a Javascript function. I've tried several ways, but can't get it working. Can someone explain what I'm doing wrong?
So here is my model:
public class Dashboard
{
public List<Note> ListNotes { get; set; }
}
I use the ListNotes on the view like this:
foreach (Note note in Model.ListNotes)
{
#Html.Raw(note.NoteText)
}
This works if I populate Model.ListNotes in the controller when the view starts...
public ActionResult DashBoard(string xsr, string vst)
{
var notes = rep.GetNotesByCompanyID(user.ResID, 7, 7);
List<Koorsen.Models.Note> listNotes = new List<Koorsen.Models.Note>();
Dashboard employee = new Dashboard
{
ResID = intUser,
Type = intType,
FirstName = user.FirstName,
LastName = user.LastName,
ListNotes = listNotes
};
return View(employee);
}
... but I need to populate ListNotes in a Javascript after a user action.
Here is my javascript to make an ajax call to populate ListNotes:
function getReminders(e)
{
var userID = '#ViewBag.CurrUser';
$.ajax({
url: "/api/WoApi/GetReminders/" + userID,
dataType: "json",
type: "GET",
success: function (notes)
{
// Need to assign notes to Model.ListNotes here
}
});
}
Here's the method it calls with the ajax call. I've confirmed ListNotes does have the values I want; it is not empty.
public List<Koorsen.Models.Note> GetReminders(int id)
{
var notes = rep.GetNotesByCompanyID(id, 7, 7);
List<Koorsen.Models.Note> listNotes = new List<Koorsen.Models.Note>();
foreach (Koorsen.OpenAccess.Note note in notes)
{
Koorsen.Models.Note newNote = new Koorsen.Models.Note()
{
NoteID = note.NoteID,
CompanyID = note.CompanyID,
LocationID = note.LocationID,
NoteText = note.NoteText,
NoteType = note.NoteType,
InternalNote = note.InternalNote,
NoteDate = note.NoteDate,
Active = note.Active,
AddBy = note.AddBy,
AddDate = note.AddDate,
ModBy = note.ModBy,
ModDate = note.ModDate
};
listNotes.Add(newNote);
}
return listNotes;
}
If ListNotes was a string, I would have added a hidden field and populated it in Javascript. But that didn't work for ListNotes. I didn't get an error, but the text on the screen didn't change.
#Html.HiddenFor(x => x.ListNotes)
...
...
$("#ListNotes").val(notes);
I also tried
#Model.ListNotes = notes; // This threw an unterminated template literal error
document.getElementById('ListNotes').value = notes;
I've even tried refreshing the page after assigning the value:
window.location.reload();
and refreshing the panel bar the code is in
var panelBar = $("#IntroPanelBar").data("kendoPanelBar");
panelBar.reload();
Can someone explain how to get this to work?
I don't know if this will cloud the issue, but the reason I need to populate the model in javascript with an ajax call is because Model.ListNotes is being used in a Kendo Panel Bar control and I don't want Model.ListNotes to have a value until the user expands the panel bar.
Here's the code for the panel bar:
#{
#(Html.Kendo().PanelBar().Name("IntroPanelBar")
.Items(items =>
{
items
.Add()
.Text("View Important Notes and Messages")
.Expanded(false)
.Content(
#<text>
#RenderReminders()
</text>
);
}
)
.Events(e => e
.Expand("getReminders")
)
)
}
Here's the helper than renders the contents:
#helper RenderReminders()
{
if (Model.ListNotes.Count <= 0)
{
#Html.Raw("No Current Messages");
}
else
{
foreach (Note note in Model.ListNotes)
{
#Html.Raw(note.NoteText)
<br />
}
}
}
The panel bar and the helpers work fine if I populate Model.ListNotes in the controller and pass Model to the view. I just can't get it to populate in the javascript after the user expands the panel bar.
Perhaps this will do it for you. I will provide a small working example I believe you can easily extend to meet your needs. I would recommend writing the html by hand instead of using the helper methods such as #html.raw since #html.raw is just a tool to generate html in the end anyways. You can write html manually accomplish what the helper methods do anyway and I think it will be easier for you in this situation. If you write the html correctly it should bind to the model correctly (which means it won't be empty on your post request model) So if you modify that html using javascript correctly, it will bind to your model correctly as well.
Take a look at some of these examples to get a better idea of what I am talking about:
http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/
So to answer your question...
You could build a hidden container to hold your list values like this (make sure this container is inside the form):
<div id="ListValues" style="display:none">
</div>
Then put the results your ajax post into a javascript variable (not shown).
Then in javascript do something like this:
$('form').off('submit'); //i do this to prevent duplicate bindings depending on how this page may be rendered futuristically as a safety precaution.
$('form').on('submit', function (e) { //on submit, modify the form data to include the information you want inside of your ListNotes
var data = getAjaxResults(); //data represents your ajax results. You can acquire and format that how you'd like I will use the following as an example format for how you could save the results as JSON data: [{NoteID ="1",CompanyID ="2"}]
let listLength = data.length;
for (let i = 0; i < listLength; i++) {
$('#ListValues').append('<input type="text" name="ListNotes['+i+'].NoteID " value="' + data.NoteID +'" />')
$('#ListValues').append('<input type="text" name="ListNotes['+i+'].CompanyID " value="' + data.CompanyID +'" />')
//for your ajax results, do this for each field on the note object
}
})
That should do it! After you submit your form, it should automatically model bind to you ListNotes! You will be able to inpsect this in your debugger on your post controller action.

set Kendo FlatColorPicker default value

How do i go about setting the Kendo FlatColorPicker default value using MVC with either ViewBag or a variable?
#{
var iconColor = ViewBag.FaviconColor;
}
#(Html.Kendo().FlatColorPicker()
.Name("faviconColor")
.Value(iconColor)
.Events(events => events
.Change("ColorChange"))
)
I tried with
.Value("ViewBag.FaviconColor")
.Value("#ViewBag.FaviconColor")
.Value(ViewBag.FaviconColor)
.Value(#ViewBag.FaviconColor)
I get a javascript error when i try to do this, there has to be a way.

Refresh Telerik Combobox list from another combobox

we are implementing an MVC solution using Telerik controls and
we have some problems refreshing the list of a Telerik ComboBox. Pratically we need to refresh the list of available values of a ComboBox every time the value selected in another ComboBox is changed. Below is our scenario:
Main ComboBox has a list of string values and we added an event;
Detail ComboBox has a list of values that depends on what is chosed from Main ComboBox;
When the event on Main ComboBox is fired the javascript calls an action in Controller;
The controller refresh the content of List02 (the datasource binded in ComboBox02)
Actually it runs all correctly but the Detail ComboBox does not refresh. What is wrong or missed?
Many Thanks for help
Main ComboBox:
<%=Html.Kendo().DropDownListFor(ourModel => ourModel.ModelPK)
.HtmlAttributes(new { #class="textboxDetails" })
.Name("combo01")
.BindTo((IEnumerable<ModelObject>)ViewData["List01"])
.DataTextField("descriptionText")
.DataValueField("valueID")
.Value(ourModel.ModelPK.ToString())
.Events(e =>
{
e.Select("onSelect");
})
%>
Detail Combobox:
<%=Html.Kendo().DropDownListFor(ourModel => ourModel.secPK)
.HtmlAttributes(new { #class="textboxDetails" })
.Name("combo02")
.BindTo((IEnumerable<ModelObject>)ViewData["List02"])
.DataTextField("descriptionText")
.DataValueField("valueID")
.Value(ourModel.Model02PK.ToString())
%>
Javascript on aspx page:
function onSelect(e) {
var dataItem = this.dataItem(e.item);
var itemPK = dataItem.valueID;
$.ajax({
type: 'POST',
url: '/controller01/action01',
data: "{'sentPK':'" + sentPK + "'}",
contentType: 'application/json; charset=utf-8',
success: function (result) {
},
error: function (err, result) {
alert("Error" + err.responseText);
}
});
}
Controller action:
[AcceptVerbs(HttpVerbs.Post)]
public void action01(model01 editModel, int sentPK)
{
//View data loads correctly
}
I do not think updating second combobox with ViewData will work in scenario:
.BindTo((IEnumerable)ViewData["List01"])
For the very first time when the page is rendered the value stored in ViewData object is used to fill the combobox but then onSelect all you are doing is, making an AJAX call to server. Server updates the ViewData object but as the combo box is already loaded with initial data, it will not be refreshed with new data.
You will have to refresh the second combobox on selection change event for first combo box.
Option 1:
Add following lines in your onSelect() success:
var combobox = $("#combo02").data("kendoComboBox");
combobox.dataSource.data(result);
Option 2:
Bind datasource of second combobox with server:
#(Html.Kendo().ComboBox()
.Name("products")
.HtmlAttributes(new { style = "width:300px" })
.Placeholder("Select product...")
.DataTextField("ProductName")
.DataValueField("ProductID")
.Filter(FilterType.Contains)
.DataSource(source => {
source.Read(read =>
{
read.Action("GetCascadeProducts", "ComboBox")
.Data("filterProducts");
})
.ServerFiltering(true);
})
.Enable(false)
.AutoBind(false)
.CascadeFrom("categories")
)
For a working example, refer this link.

Categories