kendo ui grid within a window - window becomes invisible - kendo-ui

I'm using Kendo UI 2013.1 and I have a grid within a window. The window's visibility is set to false on the page load, but when a link is clicked, I make it visible.
The problem is that whenever you try to do anything with the grid, like use the filter, or use a paging button, the window becomes invisible. When you click the link again, the window is visible again and reflects whatever the last action was - filtered results or on the next page.
I've tried several approaches that look similar to:
$("#outageWindow").kendoWindow({ visible: true });
But no luck. Here is the full code without any of my resolution attempts:
#(Html.Kendo().Window()
.Name("viewListWindow")
.Title("Complete CI List")
.Width(650)
.Actions(actions => actions.Close())
.Content(#<text>
#(Html.Kendo().Grid(chg.CIsModifiedByChange.CIsModifiedByChange) //Bind the grid to ViewBag.Products
.Name("grid")
.RowAction(row =>
{
if (row.IsAlternate)
{
//Set the background of the entire row
//row.HtmlAttributes["style"] = "background:#e0f7ff;"; this is a lighter blue
row.HtmlAttributes["style"] = "background:#dde1ff;";
}
})
.Columns(columns =>
{
columns.Bound(ci => ci.Value).Title("CI Name");
})
.Pageable() // Enable paging
.Sortable() // Enable sorting
.Filterable() // Enable filtering
)
</text>)
.Draggable()
.Visible(false)
)
<script type="text/javascript">
$(document).ready(function () {
$("#viewCI").bind("click", function () {
$("#viewListWindow").data("kendoWindow").center().open();
})
});
</script>

this solution is work fine for me,
try this
function load_grid() {
/* your grid properties here */
}
$(document).ready(function () {
$("#viewCI").bind("click", function () {
/* load window */
$("#viewListWindow").data("kendoWindow").center().open();
/* load grid into element inside window after window opened */
load_grid();
})
});

Related

Can you test if an element is scrolled to

I have a link that when clicked it will scroll to div element on the same page. Is there a way I can click on a link and determine that the element was actually scrolled to?
describe('scrolling.spec.js', () => {
it('should scroll to an element.', () => {
cy.visit('/home');
cy.get('#calculator-link').click();
//verify that the element with id payment-calculator is scrolled to
///??
});
});
Yes, you can do this.
When working with Cypress you always can ask you "how would I do this in plain JS (or with JQuery)" and in most cases, you can apply exactly the same codé in cypress.
In plain JS you probably would get getClientRect() to retrive the top of the element within it's parent. So do exactly the same in Cypress.
Also you can use get(...).should("be.visible") because an element is not visible if it is not in the view. This applies if your element have a parent container that has set a max height and a overflow: scroll (only an example, there will be more situation where this is working).
So please look at the code:
describe("scroll", () => {
beforeEach(() => {
cy.visit("scroll.html")
})
describe("by using is.visible", () => {
it("is.visible fails if not in view", () => {
cy.get("#toscroll").should("be.visible");
})
it("is.visible succeeds if element in view", () => {
cy.get("#toscroll").then($e => $e[0].scrollIntoView());
cy.get("#toscroll").should("be.visible");
})
})
describe("by using clientRect", () => {
it("fails without scrolling", () => {
cy.get("#toscroll").should($e => {
expect($e[0].getClientRects()[0].top).lessThan(100);
});
})
it("clientRect should have correct size", () => {
cy.get("#toscroll").then($e => $e[0].scrollIntoView());
cy.get("#toscroll").should($e => {
expect($e[0].getClientRects()[0].top).lessThan(100);
});
})
})
})
It shows both possibilities. My html looks like this:
<html>
<head>
<style>
#container {
height: 300px;
overflow: scroll;
}
</style>
</head>
<body>
<div id="container">
<div>---</div>
<div>---</div>
..... much more elements
<div id="toscroll">is visible</div>
<div>---</div>
..... much more elements
</div>
</body>
</html>
Explanation about the usage of "plain" JS:
Cypress provides you many assertions that can be chained off CY commands. E.g. should("exist"). But you also can pass a callback into should and this callback will be repeated until the timeout has been reached or no assertion fails.
Within this callback you can access the JQuery element that was yielded from the previous command. At this moment you can do whatever you want with this object.
I use the following custom command to test if the top of an element is visible in the area that has currently been scrolled to. It fails if the element is completely off the top or the bottom of the visible area.
/cypress/support.index.js
Cypress.Commands.add("isScrolledTo", { prevSubject: true }, (element) => {
cy.get(element).should(($el) => {
const bottom = Cypress.$(cy.state("window")).height();
const rect = $el[0].getBoundingClientRect();
expect(rect.top).not.to.be.greaterThan(bottom, `Expected element not to be below the visible scrolled area`);
expect(rect.top).to.be.greaterThan(0 - rect.height, `Expected element not to be above the visible scrolled area`)
});
});
In tests:
cy.get('#payment-calculator').isScrolledTo()
According to the docs, one could simply use scrollIntoView() chained behind cy.get() like this:
cy.get('#SomeId').scrollIntoView()

Telerik/ Kendo MVC Grid, Load grid on demand, not on page load

i found a couple examples on how to do this, and none of them are working for me.
Here is my Telerik MVC grid:
#(Html.Kendo().Grid<PlayerStatsViewModel>()
.Name("PlayerStats")
.Columns(columns =>
{
columns.Bound(o => o.PlayerId);
columns.Bound(o => o.FirstName);
})
.DataSource(dataSource => dataSource
.Ajax()
.Model(model => model.Id(p => p.PlayerId))
.Read(read => read.Action("PlayerStats_Read_Bound", "Contest").Data("getPlayerId"))
).AutoBind(false)
)
Open modal with my grid
I set autobind(false) which prevents page load. After a user clicks a link i open a modal with my grid, and need to pass in a parameter.
// open modal
$(document).on("click", "#openStatsModal", function () {
playerId = $(this).data('id'); // get parameter from click
loadPlayerStats();
});
function getPlayerId() {
return {
playerId: playerId
}
}
Make ajax call?
My click method works and i get my player id. Then i try and make my grid call.
function loadPlayerStats() {
var grid = $("#PlayerStats").data("playerStats");
alert(grid); // returns undefined
//grid.ajaxRequest(); this didnt work either
grid.dataSource.read(); // Cannot read property 'dataSource' of undefined
}
Action method
Never gets called unless i turn off autobind
public ActionResult PlayerStats_Read_Bound([DataSourceRequest]DataSourceRequest request, int playerId)
{
// some code
return Json(result)
}
Just try:
var grid = $("#PlayerStats").data("kendoGrid");
and then:
grid.dataSource.read();

How to mark Kendo Grid's cell as edited?

I'm dynamically editing some fields using JavaScript. But the problem is Kendo's dataSource doesn't recognize them as changed cells.
Grid's edit mode is InCell.
This is my current JavaScript code:
tablesGrid.tbody.find("input[type='checkbox']").each(function () {
$(this).on('change', function () {
var isChecked = $(this).prop('checked');
var dataItem = tablesGrid.dataItem($(this).closest('tr'));
var currentTr = $(this).closest('tr');
var i = $('td:visible', currentTr).index($(this).closest('td'));
var head = tablesGrid.thead.find('th:visible')[i];
var headName = $(head).prop('dataset').field;
tablesGrid.editCell($(this).closest('td'));
dataItem[headName] = isChecked;
tablesGrid.refresh();
});
});
And if you're wondering about this code, I should note that I'm using client template to show checkboxes. But I don't want the user to double click the cell for editing, once to put it in the edit mode, and another one to change the checkbox. I'm not sure if I'm using the right solution, but the JS code works for sure. If I click in the cell and put it in the edit mode, I'll see the change.
#(Html.Kendo().Grid<grid>()
.Name("grid")
.Columns(columns =>
{
columns.Bound(x => x.field)
.ClientTemplate("<input type='checkbox' class='checkbox-inline' #=field? checked='checked':''# />")
.EditorTemplateName("Checkbox");
Well, the best solution I came up with is to put the cell in edit mode when mouse enters that cell! So instead of the entire JS code in the question, I simply use this.
tablesGrid.bind('dataBound', function () {
tablesGrid.tbody.find('td').each(function () {
$(this).mouseenter(function () {
tablesGrid.editCell(this);
});
});
});
Please let me know if you have any better or more efficient way to use editable
checkboxes inside a Grid.

How do I prevent the cancel event from changing my grid row color?

I search for data and then bind to my grid. In the grid's databound event, I change the row background color according to the cell's value. This works OK. But when I click the Edit button in the grid and then click the Cancel button, the grid no longer has the background color set. I tried to call the databound event in the Cancel event, but it does not work. How do I prevent the Cancel Event from changing my grid color?
grid
#(Html.Kendo().Grid(Model)
.Name("mygrid")
.Events(e=>e.DataBound("dataBound"))
.Columns(columns =>
{
columns.Bound(p =>p.StudentName).Title("StudentName");
columns.Command(command =>
{
command.Edit().UpdateText("Edit");
command.Destroy().Text("Delete");
}).Width(160);
})
.Editable(editable => editable.Mode(GridEditMode.PopUp)
.TemplateName("SudentEditor")
.Window(configurator=>configurator.Width(500)
.Title("EditStudent")))
.Scrollable()
.Events(events=>events.Cancel("onCancel"))
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(20)
.Model(model =>
{
model.Id(p => p.Id);
})
.Read(read => read.Action("GetStudentForGrid", "Student"))
.Create(create=>create.Action("CreateSudent","Equipment"))
.Update(update => update.Action("UpdateStudent", "Student"))
.Destroy(destory=>destory.Action("DestroyStudent","Student"))
.Events(events => events.Error("error_handler"))
))
databound event
//change grid color
function dataBound(e) {
$("#mygrid tbody tr").each(function(i) {
$(this).find("td:lt(9)").css("backgroundColor", '#000000');
});
}
cancel event
//I try to call preventDefault event and close the PopUp window
//,but the background is still grey
function onCancel(e) {
//e.preventDefault();
//e.container.parent().css("display", "none");
// e.sender.clearSelection();
dataBound();
}
Just refresh the grid in the cancel event. It will fire the onDataBound event again. I had the same issue and resolved it like this:
function onCancel(e) {
$("#GridName").data("kendoGrid").refresh();
}
//change grid color
function dataBound(e) {
$("#mygrid tbody tr").each(function(i) {
$(this).find("td:lt(9)").css("backgroundColor", '#000000');
});
}
You can use grid.cancelRow() in the cancel enent,and then refresh the grid.
If you don't want to refresh the grid but run code after the event has finished instead, you can use a setTimeout() in the cancel event.
function onGridCancel(e){
setTimeout(function() {
colorMyRowsBeutifully();
}, 0);
}
See this answer from Telerik:
https://www.telerik.com/forums/grid-cancel-event
I also ran into this problem and the solutions from above didn't work for me.
But I found another solution that did the trick, to use the Edit event of the Grid to attach event handler to the Deactivate event of the Window.
Grid events:
.Events(e => {
e.DataBound("onDataBound");
e.Edit("onEdit");
})
Grid event handlers:
function onDataBound(e) {
//Conditional formatting on DataBound
formatGridRows();
}
function onEdit(e) {
//Bind deactivate event to the Popup window
e.container.data("kendoWindow").bind("deactivate", function () {
formatGridRows();
})
}
function formatGridRows() {
$("#Grid tbody tr").each(function () {
grid = $("#Grid").data("kendoGrid");
dataItem = grid.dataItem($(this));
//Conditionally format the current row
if (dataItem.Discontinued) {
$(this).find(":nth-child(3):first").css("background", "red");
}
})
}
Here's the source:
http://www.telerik.com/forums/cancel-popup-clears-grid-background-color

Kendo splitter control load right panel contents asynchronously

I have a Kendo splitter control with left/right panes. Inside the left pane I have a Kendo panel bar control that builds a navigation menu. Unfortunately I inherited this from another developer that left the company and I'm not familiar with the Kendo control.
It all works, but when the user clicks on a menu item, the entire page refreshes, That's for the birds! I want only the right panel to refresh.
Here's the code for the for the layout page:
<body>
#(Html.Kendo().Splitter().Name("splitter").Panes(panes => {
panes.Add().Size("220px").Collapsible(true).Content(#<text>
#Html.Partial("_Panelbar")
</text>);
panes.Add().Content(#<text>
<section id="main">
#RenderBody()
</section>
</text>);
}))
<script type="text/javascript">
$(document).ready(function () {
$('input[type=text]').addClass('k-textbox');
});
</script>
#RenderSection("scripts", required: false)
</body>
and here's the code for the panel partial view:
#(Html.Kendo().PanelBar().Name("panelbar")
.SelectedIndex(0)
.Items(items => {
items.Add().Text("Corporate").Items(corp =>
{
corp.Add().Text("Vendors").Action("Index", "Vendor");
corp.Add().Text("Materials").Action("Index", "CostMaterials");
corp.Add().Text("Packaging").Action("Index", "CostPackaging");
corp.Add().Text("Reports").Action("UnderConstruction", "Home", new { pageTitle = "Reports" });
});
}))
I tried replacing the .Action method on the PanelBar with LoadContentsFrom method. That replaced the content in the left pane. So I guess my question is, how do I target the right side of the splitter control?
Any help would be appreciated.
Thanks
-Alex
Your code maybe like this:
#(Html.Kendo().PanelBar().Name("panelbar")
.SelectedIndex(0)
.Items(items => {
items.Add().Text("Corporate").Items(corp =>
{
corp.Add().Text("Vendors").Url("javascript:void(0);")
.HtmlAttributes(
new {
#class= "helloWorld",
#data-href="/Vendor/Index"
});
});
}))
<script>
$document.ready(function(){
$('.helloWorld').click(function(){
var href = $(this).attr('data-href');
$('#main').load(href);
});
});
</script
UPDATE
There is one thing very important: I think the view /Vendor/Index have the same template with your current page.
It means that when you load /Vendor/Index into the right side. The right side will include entire content (include left panel again).
Solution
You have to create a new view(a template) , which just include your left menu,banner,...
Then, You have to remove all template of other views (which will be loaded into right side - /Vendor/Index , /CostMaterials/Index,...)
2.This way is not a good approach. But I think It will work.
//Reference : Use Jquery Selectors on $.AJAX loaded HTML?
<script>
$document.ready(function(){
$('.helloWorld').click(function(){
var href = $(this).attr('data-href');
$.ajax({
type: 'GET',
url: href,
success: function (data){
var rHtml = $('<html />').html(data);
$('#main').html(rHtml.find('#main'));
}
});
});
});
</script

Resources