Kendo templates and reserved words - kendo-grid

From the GridInForm C# project available from Telerik the file Index.cshtml contains this grid (among other things):
#(Html.Kendo().Grid(Model.Products)
.Name("Products")
.ToolBar(tools => tools.Create().Text("Add new product"))
.Editable(editable => editable.Mode(GridEditMode.InCell).CreateAt(GridInsertRowPosition.Bottom))
.Columns(columns =>
{
columns.Bound(p => p.Name).ClientTemplate("#= Name #" +
"<input type='hidden' name='Products[#= index(data)#].Name' value='#= Name #' />");
columns.Bound(p => p.ProductID).Hidden().ClientTemplate("#= ProductID #" +
"<input type='hidden' name='Products[#= index(data)#].ProductID' value='#= ProductID #' />");
columns.Command(command => command.Destroy()).Width(100);
})
.DataSource(dataSource => dataSource
.Ajax()
.Model(model =>
{
model.Id(p => p.ProductID);
model.Field(p => p.ProductID).Editable(false);
})
.ServerOperation(false)
)
)
And this javascript function:
function index(dataItem) {
var data = $("#Products").data("kendoGrid").dataSource.data();
return data.indexOf(dataItem);
}
My question is about finding more information about the data parameter being passed in the template to the index function (in the call to ClientTemplate). What is it and where does it come from?

This line shows the use of the index() function:
"<input type='hidden' name='Products[#= index(data)#].ProductID' value='#= ProductID #' />"
data in this line is a built in object that the Kendo framework creates when it parses the client template. It represents the data object for that particular row.
You can read a bit about the data object here: http://docs.telerik.com/kendo-ui/getting-started/using-kendo-with/aspnet-mvc/helpers/grid/faq#how-do-i-use-a-javascript-function-in-a-column-client-template? under the question titled "How do I use a JavaScript function in a column client template?"
If you want to know specifically what it looks like, you can add a console.wirte(JSON.stringify(dataItem)) to the index() function to see it's exact structure.
edit
Additionally, the client template is just a text string that the Kendo Javascript parses as each column in each row is being created. At that time, it has the data object for that row which it uses to insert the values into the grid. The MVC is just a wrapper for the Javascript libraries that actually generate the HTML in the document.

Related

How to do a breakline in yii2?

I'm trying to combine two data into one column. I already managed to combine two data in one column. But my problem is I don't know how to do a break line to separate the data. I have tried this way but doesn't work.
This is my code
'NAME_PROG_ENG'.'REMARKS' => ['label' => "Programme Name",'value' => function ($data) {return ($data->NAME_PROG_ENG)."\r\n".nl2br("Previously known as: ".($data->REMARKS));}],
I think you refer to GridView component.
Some explanation:
'NAME_PROG_ENG'.'REMARKS' =>
the array index is the model field name, you can't combine 2 columns just by concatenating the column name. In this way you just define a column in the grid wich is not connected to the model. This is not an error, is just to notice that this does not give you the expected result.
'value' => function ($data) {return ($data->NAME_PROG_ENG)."\r\n".nl2br("Previously known as: ".($data->REMARKS));}
Between $data->NAME_PROG_ENG and $data->REMARKS you put a "\r\n" which is fine, but you apply nl2br() function only to the second part of the string.
Now about Gridview. Text are automatically converted to entities, this is a security feature to avoid script injection from user input. If you plan to use input from an untrusted user, ensure that you clean it using htmlpurifier before saving it in database or before showing it (in your 'value'=>... function)
https://www.yiiframework.com/search?language=en&version=2.0&type=guide&q=htmlpurifier
You can bypass html entity conversion by specifies the output format as raw in grid column option
'format'=>'raw'
So you column definition should be something like
'prog_and_remark_combined' => [
'format' => 'raw',
'label' => "Programme Name",
'value' => function ($data) {
return nl2br(
$data->NAME_PROG_ENG .
"\r\nPreviously known as: " .
$data->REMARKS
);
}
],
Gridview allow a short notation
https://www.yiiframework.com/doc/api/2.0/yii-grid-gridview#$columns-detail
which is like this
<column name>:<fomat>:<label>
your code can be as follow as well
'prog_and_remark_combined:raw:Programme Name' => [
'value' => function ($data) {
return nl2br(
$data->NAME_PROG_ENG .
"\r\nPreviously known as: " .
$data->REMARKS
);
}
],
Last note, if the fields does not contain new line to be converted, just concatenate them without using nltobr() function
return $data->NAME_PROG_ENG . "<br>Previously known as: " . $data->REMARKS

Kendo MVC Razor Grid Custom Command does not have Action Definition

I am new to Kendo and are trying to add a custom command to a grid.
I have been going over example pages, StackOverflow, and Telerik's site and found multiple examples that has the following:
columns.Command(command =>
{
command.Custom("Details").Text("Show Details").Action("Details", "Billing");
});
When I try to use this, I get the following error:
'GridCustomActionCommandBuilder' does not contain a
definition for 'Action' and the best extension method overload
'UrlHelperExtensions.Action(IUrlHelper, string, object)' requires a
receiver of type 'IUrlHelper'
I then tried this example from telerik:
columns.Template(#<text>#Html.ActionLink("Edit", "Home", new { id = item.ProductID })</text>);
But get this error:
Cannot convert lambda expression to type 'string' because it is not a
delegate type
Just to confirm what is causing the error, then took out the ActionLink and used only this:
columns.Template(#<text>
<div>help me!!</div>
</text>);
and got the same error:
The total code snippet looks like this:
#(Html.Kendo().Grid<OrganisationEmployeesViewModel>()
.Name("grid")
.Columns(columns =>
{
columns.Bound(p => p.EmployeeID).Visible(false);
columns.Template(#<text>
<div>help me!!</div>
</text>);
})
.Pageable()
.Sortable()
.Scrollable()
.Filterable()
.HtmlAttributes(new { style = "height:550px;" })
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(20)
.Read(read => read.Action("Employees_Read", "Organisations"))
)
.Deferred()
)
I am using existing samples but don't know what is wrong.
I found a way for this to work:
columns.Template("<a href='" +
Url.Action("ControllerAction", "Controller") +
"?Parameter=#= RecID #'" +
">DisplayText</a>");
This can also be applied to a bound column like this:
columns.Bound(p => p.Name).ClientTemplate("<a href = '" +
Url.Action("Details", "Employees") +
"/#= EmployeeID #'" +
">#=Name#</a>");
And should you want to have a Custom Toolbar Action on the Kendo Grid:
I am using the standard bootstrap classes to apply defaults:
.ToolBar(t => t.ClientTemplate("<a class='k-button k-button-icontext k-grid-add' href='" +
Url.Action("OrganisationCreate", "Employees", new { OrganisationId = Model.OrganisationID }) +
"'><span class='k-icon k-add'></span>Add new Employee</a>") )

How can I ensure Kendo Grid passes a numeric value with the correct separator to ASP.NET MVC?

I have a simple grid that uses a custom popup editor template. In the template, I'd like to use a Numeric Textbox.
Due to localization, the application keeps trying to use a comma to separate decimals in the numeric values. When these values are passed to the ASP.NET MVC back-end, the value is lost and null is passed. How can I ensure the posted value has a period separator?
I have tried setting the underlying field values to 2.5 instead of 2,5 in the grid's Save event, as well as tried to overwrite the e.model.WeightKg to 2.5. The value is still passed with a comma separator, as shown by inspecting the form data in the request.
My grid:
#(Html.Kendo().Grid<PackageViewModel>()
.Name("PackageGrid")
.Columns(columns => {
columns.Bound(o => o.PackageCode);
columns.Bound(o => o.WeightKg);
columns.Command(o => o.Edit());
})
.DataSource(d => d
.WebApi()
.Model(m => m.Id(o => o.PackageCode))
.Read(c => c.Url(Url.HttpRouteUrl("DefaultApi", new { controller = "Packages" })))
.Create(c => c.Url(Url.HttpRouteUrl("DefaultApi", new { controller = "Packages" })))
.Destroy(c => c.Url(Url.HttpRouteUrl("DefaultApi", new { controller = "Packages" id = "{0}" })))
.Update(c => c.Url(Url.HttpRouteUrl("DefaultApi", new { controller = "Packages" id = "{0}" })))
.PageSize(20)
)
.Editable(e => e.Mode(GridEditMode.PopUp).TemplateName("Package"))
.Selectable()
.Deferred()
)
The numeric textbox in the template:
#Html.Kendo().NumericTextBoxFor(m => m.WeightKg).Decimals(8)
And finally, the unparsed form data, followed by the parsed form data:
sort=&group=&filter=&PackageCode=DOOS-B&WeightKg=2%2C5
sort:
group:
filter:
PackageCode:DOOS-B
WeightKg:2,5

Cakephp 3 & Ajax, send $.get additional data

I try to send custom data using $.get from jquery but cakephp 3 does not recognize the variables.
Here is my function in controller:
public function view($cat,$id,$page){
$comments = $this->Comments->find('all')->where(['category =' => $cat, 'AND' => ['category_id =' => $id]])->order(['comments.created' => 'DESC'])
->contain([
'Reports' => function($q){return $q->where(['user_id =' => $this->Auth->user('id')]);},
'Chars' => function($q){ return $q->select(['id','name','class','race','level','guild_id', 'user_id'])
->contain(['Guilds' => function($q){ return $q->select(['id','name']);
}]);
}])->limit(3)->page($page);
if($cat == 'Videos'){
$subject = $this->Comments->Videos->get($id);
}
$category = $cat;
$this->set(compact('subject','comments','category'));
}
}
And here's the .js
$('.more').click(function(){
$.get($(this).attr('href'),{cat:'Videos',id:'44',page:'2',function(data){
$('.coms').empty().append(data);
});
return false;
});
And the link:
<?= $this->Html->link('More', ['controller' => 'Comments','action' => 'view'], ['class' => 'btn btn-primary more']) ?>
The fix values in the .js is for the test, it works if I send the data in the link with $.get(href) but I want to know how to pass custom data in the $.get request.
Thank you for your help
CakePHP doesn't magically map query string parameters to method arguments, that's not even supported by routes.
You can access query string paramters via the request object
$this->request->query('cat');
See also http://book.cakephp.org/3.0/en/controllers/request-response.html#query-string-parameters
The solution
Hi, I did a little api to get the data I need from a json array.
So I created an ApiController to do all the ajax requests I need. Here is test example:
<?php
namespace App\Controller;
use App\Controller\AppController;
use Cake\ORM\TableRegistry;
class ApiController extends AppController
{
public function test($id)
{
$UsersTable = TableRegistry::get('Users');
$users = $UsersTable->find()->where(['id <' => $id]);
$this->set(compact('users'));
}
}
?>
I want to get the list of all my users from an ajax call (that's the worst idea ever but it's just for the test ;))
Now I need to enable json for this view. For this, I need to go in config/routes.php to add this:
Router::scope('/api', function($routes){
$routes->extensions(['json']);
$routes->connect('/test/*', ['controller' => 'Api', 'action' => 'test', '_ext' => 'json']);
});
Now when I go on http://localhost/mywebsite/api/test/100, I have a json array of all the users with an id < 100, ready to get pulled by an ajax script.
'_ext' => 'json'
means you don't have to go on api/test.json to display the json array
Now on a random view in a random controller, I put a button to try all this and I call my javascript file to do my ajax request.
<button class="test">Test button</button>
<?= $this->Html->script('test', ['block' => true]) ?>
Now in my test.js:
$(document).ready(function(){
var value = 100;
$('.test').click(function(){
$.get('/api/test/' + value, function(data){
console.log(data);
});
});
});
I click the button and the log shows an array with all the users I wanted in my console when I push F12 (on chrome).
Hope this will help someone

Submit AngularJS form with CodeIgniter

Let me preface this by saying I'm new to AngularJS & CodeIgniter.
Trying to create a single page app. In the center it displays news stories. On the side is a form to submit new stories. I'm to the point where the stories display fine from the DB. But when I try to create new stories from the form on the side, it enters 0 into the DB. I assume I have an issue with my function in the model. And it's probably as basic as not having the information encoded correctly to pass between MVC.
index.php
<div class="span2" ng-controller="NewStoryCtrl">
<h4>New Story</h4>
<form name="newStory">
<label for="title">Title: </label>
<input type="text" name ="title" ng-model="news.title" required>
<label for="text">Text: </label>
<textarea type="text" name="text" ng-model="news.text"required></textarea>
<button ng-click="createNews()">Submit</button>
</form>
controller.js
function NewStoryCtrl($scope, $http) {
$scope.news = {title:$scope.title, text:$scope.text};
$scope.createNews = function(){
$http.post('/ci/index.php/news/create/',$scope.news);
};}
news.php (controller)
public function create() {
$this->news_model->set_news();
}
news_model.php (model)
public function set_news() {
$this->load->helper('url');
$slug = url_title($this->input->post('title'), 'dash', TRUE);
$data = array(
'title' => $this->input->post('title'),
'slug' => $slug,
'time' => time(),
'text' => $this->input->post('text')
);
return $this->db->insert('news', $data);
}
The stuff in the model is leftover from my initial CI news tutorial. That's why I assume the error is here.
What's the best way to pass the information from the controllers.js to the model?
As expected, my issue was with not getting the right type of data. Controller was expecting a variable, but in Angular controller I was passing it as JSON. I hadn't ever gone through decoding.
news.php (controller)
public function create() {
$data = json_decode(file_get_contents('php://input'), TRUE);
$this->news_model->set_news($data);
}
And then in the model, I just needed to pass it as a parameter to set_news(). I ended up changing some variable names, just for personal clarification.
*news_model.php*
public function set_news($data) {
$this->load->helper('url');
$slug = url_title($data['title'], 'dash', TRUE);
$retval = array(
'title' => $data['title'],
'slug' => $slug,
'time' => time(),
'text' => $data['text']
);
return $this->db->insert('news', $retval);
}
I haven't used Angular.js, but your data format is probably correct. For example, Backbone sends a single $_POST variable called model with json encoded data, as I have used it.
It is imperative that you use Firebug, Webdev or other tools to see what is going on when you try to do AJAX work like this; otherwise you will go crazy . Look at the variable being sent to your backend - it is probably described, an encoded single var you will need to collect, json_decode, CLEAN & VALIDATE and then use.