How to pass selected row of Kendo grid data to controller - kendo-grid

I've got a kendo grid with an image near it that will act like a button. When pressed, it will call a controller method. I want to send the selected row data to that method.
VIEW
<a href="#" id="ic_open" class="tooltip2" title="Abrir">
<span title="">
<img class="toolbar-icons" src="../../Images/open.png"/>
</span>
</a>
...
<div id="datagrid">
#(Html.Kendo().Grid(Model)
.Name("datagrid_Concessoes")
.Columns(columns =>
{
columns.Bound(c => c.Id).Width(70);
columns.Bound(c => c.Code);
columns.Bound(c => c.Description);
columns.Bound(c => c.CreationDate);
columns.Bound(c => c.CreationUser);
})
.HtmlAttributes(new { style = "height: 534px;" })
.Scrollable()
.Sortable()
.Selectable()
.Pageable(pageable => pageable
.Refresh(true)
.ButtonCount(5))
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(15)
.Read(read => read.Action("GetConcessoes", "MasterData"))
)
)
</div>
And the script:
<script type="text/javascript">
$(function () {
$('.tooltip2').click(function () {
var id = this.id;
$.get('#Url.Content("GetPartialView")',
{ "id": id },
function (data) {
$('#div-for-partial').html(data);
});
});
});
</script>
This script sends the link's id (ic_open) to the controller successfully. I want to send the selected row data, via this same function or some other (doesn't matter), to the controller so I can manipulate that info.
EDIT
Controller method
public ActionResult GetPartialView(string id)
{
switch (id)
{
case "":
return PartialView("_Concessoes");
case "tab1":
return PartialView("_Concessoes");
case "tab2":
return PartialView("_AutoEstradas");
case "ic_open":
return PartialView("_NovaConcessao");
}
return RedirectToAction("Index");
}

Your Script should be as below:
<script type="text/javascript">
$(function () {
$('.tooltip2').click(function () {
var id = this.id;
var concessoesGrid = $("#datagrid_Concessoes").data("kendoGrid");
var row = concessoesGrid.select();
$.get('#Url.Content("GetPartialView")',
{ "id": id, "modelData":row },
function (data) {
$('#div-for-partial').html(data);
});
});
});
</script>
Now there will be change on your controller side also:
public ActionResult GetPartialView(string id, ModelClass modelData)
{
//here you can access the modelData Object which will have the value of Selcted row of Grid
switch (id)
{
case "":
return PartialView("_Concessoes");
case "tab1":
return PartialView("_Concessoes");
case "tab2":
return PartialView("_AutoEstradas");
case "ic_open":
return PartialView("_NovaConcessao");
}
return RedirectToAction("Index");
}
NOTE: if you want to pass multiple selected grid records to controller then you will need to change the controller argument to accept List of objects.

I am using KendoJS but I believe this would also work on your side too:
var grid = $("yourgrid's id or class");
var selectedRow;
grid.change = function()
{
grid.select().each(function () {
var dataItem = grid.dataItem($(this));
selectedRow = dataItem;
});
}
I also found this for Kendo ASP.NET MVC:
#(Html.Kendo().Grid(Model)
.Name("grid")
.Events(e => e
.DataBound(#<text>
function() {
//Handle the dataBound event inline
}
</text>)
.Change(#<text>
var selectedRow;
function() {
var grid = this;
grid.select().each(function () {
var dataItem = grid.dataItem($(this));
selectedRow = dataItem;
});
}
</text>)
)
)
After getting the selected row, the rest is easy. Just send the value you want into your hidden value element on your cshtml page or just call the ajax method for your controller right over on your JavaScript code.

Related

How to print json api data in reactjs

I'm fetching json api details through GET request and trying to print it. Getting an error:
Error in the console is Uncaught ReferenceError: allUsers is not defined
const Dashboard = ({status, juser}) => {
const [allUsers, setAllUsers] = React.useState([]);
const id = juser.actable_id;
console.log(id); //getting id here as 1
const getAllusers = () => {
axios
.get(`http://localhost:3001/user/${id}`, { withCredentials: true })
.then((response) => {
console.log(response.data);
setAllUsers(response.data);
})
.catch((error) => {
console.log(" error", error);
});
};
React.useEffect(() => {
getAllusers();
}, []);
{allUsers.map((job_seeker, index) => {
return (
<div>
<p>{job_seeker.name}</p>
</div>
);
})}
}
export default Dashboard;
I'm new to react. Any help is appreciatable.
const [state, setState] = React.useState([]);
the state is where your data is located and setState is function to reset the state from anywhere,
so on your code,
const [jobseekers, allUsers] = React.useState([]); // change string to array
jobseekers is the variable where your data is located and allUsers is the function to store data into state.
set data to state using allUsers function,
const getAllusers = () => {
axios
.get(`http://localhost:3001/user/${id}`, { withCredentials: true })
.then((response) => {
allUsers(response.data);
})
.catch((error) => {
console.log(" error", error);
});
};
and map from jobseekers
{jobseekers.map((job_seeker, index) => {
return (
<div>
<p>{job_seeker.name}</p>
</div>
);
})}
Also I would suggest to rename your state and setState as,
const [allUsers, setAllUsers] = React.useState([]);
You didn't pass the value of response to allUsers, instead, you just created a new variable. So change
const allUsers = response.data;
to:
allUsers(response.data)
Besides, you can also improve the way that you have used useState. You have initialized it as an empty string while you'll probably store an array from response in jobseekers. So, initialize it as an empty array.
const [jobseekers, allUsers] = React.useState([]);

How to get the length of the response from a fetch request?

I have got series of data that contains some objects in one array(json file) and it will be shown by react.
Here is my code:
class App extends React.Component {
constructor(props){
super(props);
this.state = {
data: [],
library:null,
perPage: 20,
currentPage: 1,
maxPage: null,
filter: ""
};
}
componentDidMount() {
fetch('/json.bc')
// Here I want to get the length of my respose
.then(response => response.text())
.then(text => {
var Maindata = JSON.parse(text.replace(/\'/g, '"'))
this.setState(state => ({
...state,
data: Maindata
}), () => {
this.reorganiseLibrary()
})
}).catch(error => console.error(error))
}
reorganiseLibrary = () => {
const { filter, perPage , data } = this.state;
let library = data;
if (filter !== "") {
library = library.filter(item =>
item.hotelinfo.hotelsearch.realname.toLowerCase().includes(filter)
);
}
library = _.chunk(library, perPage);
this.setState({
library,
currentPage: 1,
maxPage: library.length === 0 ? 1 : library.length
});
};
// Previous Page
previousPage = () =>
this.setState(prevState => ({
currentPage: prevState.currentPage - 1
}));
// Next Page
nextPage = () =>
this.setState(prevState => ({
currentPage: prevState.currentPage + 1
}));
// handle filter
handleFilter = evt =>
this.setState(
{
filter: evt.target.value.toLowerCase()
},
() => {
this.reorganiseLibrary();
}
);
// handle per page
handlePerPage = (evt) =>
this.setState({
perPage: evt.target.value
}, () => this.reorganiseLibrary());
// handle render of library
renderLibrary = () => {
const { library, currentPage } = this.state;
if (!library || (library && library.length === 0)) {
return <div class="tltnodata">no result!</div>;
}
return library[currentPage - 1].map((item, i) => (
<input type="hidden" value={item.hotelinfo.hotelsearch.hotelid} name="hotelid"/>
));
};
render() {
const { library, currentPage, perPage, maxPage } = this.state;
return (
<div className="Main-wrapper">
<div class="filter_hotelname"><input value={this.state.filter} onChange={this.handleFilter} class="hotelName" /></div>
<div class="countHotel"> <span class="numbersearch"></span> // Here I want two show the count of items </div>
<div className="wrapper-data">
{this.renderLibrary()}
</div>
<div id="page-numbers">
<div class="nexprev">
{currentPage !== 1 && (
<button onClick={this.previousPage}><span class="fa-backward"></span></button>
)}
</div>
<div className="data_page-info">
{this.state.currentPage} از {this.state.maxPage}
</div>
<div class="nexprev">
{(currentPage < maxPage) && (
<button onClick={this.nextPage}><span class="fa-forward"></span></button>
)}
</div>
</div>
</div>
);
}
}
ReactDOM.render(<App/>, document.getElementById('Result'));
I want to find the length of response from a request with fetch. Also I want to know how to find the count of items that will be shown by renderLibrary . For example in json.bc we have 4 objects I want to show 4 in numbersearch span.
Using Fetch API you can find json response item length by running below code snippet. I have also added comment in code as well.
fetch('https://jsonplaceholder.typicode.com/todos')
.then(response => {
//below method return promise based response by converting stream object to json
return response.json();
}).then(json => {
//Once succcessful callback return you can find length of number of item
console.log(json);
alert("Number of item:"+json.length)
})
fetch('https://jsonplaceholder.typicode.com/todos')
.then(response => {
//below method return promise based response by converting stream object to json
return response.json();
}).then(json => {
//Once succcessful callback return you can find length of number of item
alert(json.length)
})
You can use the length of the data array from the state to distinguish the number of items.
Since arrays start at 0, you will need to increment the count by one. Here's an example snippet below that you can use in your code sample.
<div class="countHotel"><span class="numbersearch">{this.state.data && this.state.data.length + 1}</span></div>

What's the best way to mock a nested function?

consider a function
exports.projectNotifyLaunch = (admin, functions) => {
return functions.database.ref("/projects/{pid}").onCreate(snap => {
const { title } = snap.val();
const notification = {
title: `${title} just launched!`,
body: `We just heard about a new cryptocurrency project called ${title}`
};
return admin.messaging().sendToTopic("premium", { notification });
});
};
How should I mock deeply nested functions such as
functions.database.ref("/projects/{pid}").onCreate(snap => {});
or
admin.messaging().sendToTopic("premium", { notification });
in Jest? I want to fire off the snap=>{} callback and assert against the value of notification.
I was able to make this work
This works but it's quite verbose. I'm wondering if there is a better way, or a type of testing I'm not aware of with Jest.
describe("send notification to premium users on new project", () => {
// INPUTS
const snap = {
val: () => ({
title: "Test Title"
})
};
const functions = {
database: {
ref: () => ({
onCreate: callback => callback(snap)
})
}
};
// outputs
let topicStub = null;
let notificationStub = null;
const admin = {
messaging: () => ({
sendToTopic: (topic, notification) => {
topicStub = topic;
notificationStub = notification;
}
})
};
projectNotifyLaunch(admin, functions);
test("title is correct", () => {
expect(notificationStub.notification.title).toBe(
"Test Title just launched!"
);
});
test("topic is premium", () => {
expect(topicStub).toBe("premium");
});
});

Populating ASP.NET MVC Kendo Grid Via Ajax Call

I have an MVC Kendo Grid and I want to fill it via a jQuery Ajax Call. I used jQuery 'each' method to do it like this :
function FillRowsByRequest(reqRow) {
var readDataUrl = '#Url.Action("GetGoodsByReq")';
var targetGrid = $("#storeReceiptRowsGrid").data("kendoGrid");
$.get(readDataUrl, { reqseq: reqRow }, function (d, t, j) {
var counter = 0;
targetGrid.cancelChanges();
$(d).each(function (i, e) {
targetGrid.dataSource.insert(counter++, {
GOOD_ID: e.GOOD_ID,
GOOD_CODE: e.GOOD_CODE,
GOOD_CODE_DESC: e.GOOD_CODE_DESC,
GOOD_DESC: e.GOOD_DESC
});
});
});
}
I can see my Kendo Grid that is filled with data ( not completely ) but the thing is that when I click on the Save button, it does not trigger the Save Action Method and consequently nothing is inserted in the table and Grid contains nothing after it is refreshed.
#(Html.Kendo()
.Grid<Tpph.Models.STORE_RECEIPT_ROW>()
.Name("storeReceiptRowsGrid")
.Columns(columns =>
{
columns.Bound(o => o.GOOD_ID).Title("Good ID").HtmlAttributes(new { #class = "goodid" }).Visible(false);
columns.Bound(o => o.GOOD_CODE).Title("Good Code").HtmlAttributes(new { #class = "goodcode" }).Width(100);
columns.Bound(o => o.GOOD_CODE_DESC).Title("Good Code Desc").HtmlAttributes(new { #class = "goodcodedesc" }).Width(100);
columns.Bound(o => o.GOOD_DESC).Title("Good Desc").HtmlAttributes(new { #class = "gooddesc" }).Width(155);
})
.ToolBar(toolbar =>
{
toolbar.Create().Text("New Row").HtmlAttributes(new { #class = "k-primary", style = "background-color: #e6ffe6; border-color: #10c4b2; min-width: 100px; color: black;" });
toolbar.Save().Text("Save").SaveText("Save").CancelText("Cancel").HtmlAttributes(new { #class = "k-primary", style = "background-color: #e6ffe6; border-color: #10c4b2; min-width: 100px; color: black;" });
})
.ColumnMenu()
.Selectable(s => s.Type(GridSelectionType.Row))
.Sortable()
.Editable(editable => editable.Mode(GridEditMode.InCell).DisplayDeleteConfirmation("Delete?"))
.Filterable()
.Groupable()
.Scrollable()
.Pageable(p => p.Refresh(true))
.Resizable(resize => resize.Columns(true))
.Reorderable(reorder => reorder.Columns(true))
.DataSource(dataSource => dataSource
.Ajax()
.Events(ev => ev.RequestEnd("storeReceiptRowsGridOnRequestEnd"))
.Batch(true)
.ServerOperation(true)
.Model(model =>
{
model.Id(p => p.GOOD_ID);
})
.Read(read => read.Action("StoreReceiptRowsRead", "StorageForms"))
.Update(u => u.Action("StoreReceiptRowsEdit", "StorageForms"))
.Create(c => c.Action("StoreReceiptRowsCreate", "StorageForms"))
.Destroy(de => de.Action("StoreReceiptRowsDestory", "StorageForms")))
.Events(ev =>
{
ev.DataBound("storeReceiptRowsGridOnBound");
})
)
How can I do this ?
After lots of struggling with this issue, I finally found out that the Kendo Grid triggers the CRUD Action Methods only when the "dirty" attribute of a row is set to true. ( dirty flag is a tiny little red triangle which appears in the corner of a cell when you edit that cell ). So the solution to this issue is setting dirty flag of each row to true like this :
.set("dirty", true);
So my final JavaScript Code is like this :
function FillRowsByRequest(reqRow) {
var readDataUrl = '#Url.Action("GetGoodsByReq")';
var targetGrid = $("#storeReceiptRowsGrid").data("kendoGrid");
$.get(readDataUrl, { reqseq: reqRow }, function (d, t, j) {
var counter = 0;
targetGrid.cancelChanges();
$(d).each(function (i, e) {
targetGrid.dataSource.insert(counter++, {
GOOD_ID: e.GOOD_ID,
GOOD_CODE: e.GOOD_CODE,
GOOD_CODE_DESC: e.GOOD_CODE_DESC,
GOOD_DESC: e.GOOD_DESC
}).set("dirty", true);
});
});
}

Error event handling causes Read to not be called

Below is my PartialView for a Kendo Grid. As of now, my Parts_Read action is NOT called. But, if I comment out
.Events(events => events.Error("error_handler"))
Then everything works fine. Any ideas of why this is happening?
#using Kendo.Mvc.UI;
#using eRPortalDashboard.Models
#model PMPartsViewModel
#{
int PMNumber = Model.PMNumber;
string uniqueName = Model.PartsGrid.ID;//Regex.Replace(Guid.NewGuid().ToString(), "[^A-Za-z]+", "");
bool enableToolbar = Model.PartsGrid.EnableToolbar;
bool enablePageable = Model.PartsGrid.Pageable;
bool enableSortable = Model.PartsGrid.Sortable;
bool enableColumnMenu = Model.PartsGrid.EnableColumnMenu;
bool enableGroupable = Model.PartsGrid.Groupable;
bool enableColumnResizing = Model.PartsGrid.AllowColumnResizing;
bool enableScrolling = Model.PartsGrid.Scrollable;
bool enableSelection = Model.PartsGrid.Selectable;
}
#(Html.Kendo().Grid<PartViewModel>()
.Name(uniqueName)
.Columns(columns =>
{
columns.Bound(c => c.ItemNumber);
columns.Bound(c => c.Description);
})
.ToolBar(toolBar =>
{
toolBar.Custom().Text("Test Button").Url("#").HtmlAttributes(new { id = "testButton" });
})
.Pageable(pager => pager
.Input(false) //Using pageable.numeric and pageable.input at the same time is not recommended.
.Numeric(true)
.Info(true)
.PreviousNext(true)
.Refresh(true)
.PageSizes(new object[] { 5, 10, 20, 50, "all" })
.Enabled(enablePageable)
)
.Selectable(s => s.Mode(mode: GridSelectionMode.Multiple).Enabled(enableSelection))
.AllowCopy(enableSelection) //selectable needs to be enabled and set to multiple
.Sortable(s => s.SortMode(GridSortMode.MultipleColumn).Enabled(enableSortable))
.ColumnMenu(c => c.Enabled(enableColumnMenu))
.Groupable(g => g.Enabled(enableGroupable))
.Scrollable(s => s.Height("auto").Enabled(enableScrolling))
.Resizable(resize => resize.Columns(enableColumnResizing))
//.Events(events => events.DataBound(uniqueName + "_updateGrid").Change(uniqueName + "_updateGrid"))
.DataSource(dataSource => dataSource
.Ajax()
.ServerOperation(true)
.Events(events => events.Error("error_handler"))
.Read("Parts_Read", "PM", new { PMNumber = PMNumber })
)
)
<script type="text/javascript">
function error_handler(e) {
if (e.errors) {
var message = "Errors:\n";
$.each(e.errors, function (key, value) {
if ('errors' in value) {
$.each(value.errors, function () {
message += this + "\n";
});
}
});
alert(message);
}
}
The main crux of my issue was the fact that error_handler was declared after my MVC code, thereby making it unable to bind to the method.
Apparently, with Kendo (maybe others), when using Partial Views, the javascript function must be declared BEFORE it is used in Razor syntax for that view.
see also: telerik forum post