I'm trying to define a ProductRow and ProductCategoryRow from Thinking in React.
productRow.re
let component = ReasonReact.statelessComponent("ProductRow");
let make = (~name, ~price, _children) => {
...component,
render: (_self) => {
<tr>
<td>{ReasonReact.stringToElement(name)}</td>
<td>{ReasonReact.stringToElement(price)}</td>
</tr>
}
};
productCategoryRow.re
let component = ReasonReact.statelessComponent("ProductCategoryRow");
let make = (~title: string, ~productRows, _children) => {
...component,
render: (_self) => {
<div>
<th>{ReasonReact.stringToElement(title)}</th>
</div>
}
};
I believe that I need to map over the productRows, i.e. List of ProductRow's, with a function of: productRow => <td>productRow</td>.
How can I do that in this example?
Or, if I'm completely off the mark, please explain how I can achieve the above.
In the 'Thinking in React' page, the component nesting hierarchy is such that a ProductTable contains several ProductRows. We can model that in ReasonReact by mapping over an array of products and producing ProductRows as the output. E.g.:
type product = {name: string, price: float};
/* Purely for convenience */
let echo = ReasonReact.stringToElement;
module ProductRow = {
let component = ReasonReact.statelessComponent("ProductRow");
let make(~name, ~price, _) = {
...component,
render: (_) => <tr>
<td>{echo(name)}</td>
<td>{price |> string_of_float |> echo}</td>
</tr>
};
};
module ProductTable = {
let component = ReasonReact.statelessComponent("ProductTable");
let make(~products, _) = {
...component,
render: (_) => {
let productRows = products
/* Create a <ProductRow> from each input product in the array. */
|> Array.map(({name, price}) => <ProductRow key=name name price />)
/* Convert an array of elements into an element. */
|> ReasonReact.arrayToElement;
<table>
<thead>
<tr> <th>{echo("Name")}</th> <th>{echo("Price")}</th> </tr>
</thead>
/* JSX can happily accept an element created from an array */
<tbody>productRows</tbody>
</table>
}
};
};
/* The input products. */
let products = [|
{name: "Football", price: 49.99},
{name: "Baseball", price: 9.99},
{name: "Basketball", price: 29.99}
|];
ReactDOMRe.renderToElementWithId(<ProductTable products />, "index");
Related
I am new to ag-grid with Angular. I have simple html table to list users. And i want to use ag-grid for this. There are few columns which shouldn't be displayed if there is no permission. I am not sure how to achieve this using ag-grid. Can anyone please help me how to achieve this?
Existing html table:
<table>
<thead>
<tr>
<th width="30"> </th>
<th>Name</th>
<ng-container *requireAnyPermission="[SensitiveAccessPermission]">
<th>Modified by</th>
<th>Modified date</th>
</ng-container>
<th *requireAnyPermission="[SensitiveAccessPermission]">Active</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let person of people">
<td> </td>
<td data-label="Name">{{ person.name }}</td>
<ng-container *requireAnyPermission="[SensitiveAccessPermission]">
<td data-label="Modified by">{{ person.modifiedBy }}</td>
<td data-label="Modified date">
{{ person.modified | dateTimeFormat }}
</td>
</ng-container>
<td *requireAnyPermission="[SensitiveAccessPermission]" data-label="Active">
<ng-container *ngIf="person.isActive; then checkTemplate"></ng-container>
</td>
</tr>
</tbody>
</table>
I have the ag-grid column definition as below:
const COLUMNS: ColDef[] = [
{ headerName: '', field: '' },
{ headerName: 'Name', field: 'name', filter: true },
{ headerName: 'Modified by', field: 'modifiedBy', filter: true },
{ headerName: 'Modified date', field: 'modified', filter: true },
{ headerName: 'Active', field: 'isActive', filter: true },
];
How to achieve the same with ag-grid.
*requireAnyPermission is custom directive
#Directive({
// tslint:disable-next-line: directive-selector
selector: '[requireAnyPermission]'
})
export class RequireAnyPermissionDirective implements OnDestroy {
private _onDestroy = new Subject();
private _reverse = false;
private _anyPermissions: Array<string | PermissionCodeWithMask>;
#Input() set requireAnyPermission(
permissions: Array<string | PermissionCodeWithMask>
) {
this._anyPermissions = permissions;
this.updateView();
}
#Input() set requireAnyPermissionReverse(reverse: boolean) {
this._reverse = reverse;
this.updateView();
}
constructor(
private templateRef: TemplateRef<HTMLElement>,
private viewContainerRef: ViewContainerRef,
private userService: UserService
) {}
ngOnDestroy(): void {
this._onDestroy.next();
}
private updateView() {
if (this._anyPermissions) {
this.userService
.userHasAnyPermissions(this._anyPermissions)
.pipe(takeUntil(this._onDestroy))
.subscribe((hasPermission) => {
this.viewContainerRef.clear();
if (
(hasPermission && !this._reverse) ||
(!hasPermission && this._reverse)
) {
this.viewContainerRef.createEmbeddedView(this.templateRef);
}
});
}
}
}
Thanks
You can do that by either constructing the column definitions array programmatically based on the permissions the user have OR remove the columns you want to hide from COLUMNS on component initialization
In both cases you would have to call
gridOptions.api.setColumnDefs(columnDefs);
after you are done
Look at updating column defs example here
You wanna do something similar.
You can show/hide columns:-
this.gridColumnApi.setColumnsVisible([...visibleCols], true); // show columns
this.gridColumnApi.setColumnsVisible([...hiddenCols], false); // hide columns
If you want those column, not available in the grid:-
when creating columnDefs for grid, dont add in columnDefs conditionally
In my opinion this is simple method (* For Big Project and multiple change)
First get all column list for grid like.
getKeys(obj: []) {
var keys = [];
for (var key in obj) {
keys.push(key);
}
return keys;
}
this getKeys method give you all ColumnName of over array
//item is json response from over server.
var columns = this.getKeys(item[0]);
var colObj = {};
var gridcolumnDefs = [];
for (var i = 0; i & lt; columns.length; i++) {
var visible = true;
switch (columns[i].toLocaleLowerCase()) {
case 'columnname1':
colObj = {
field: columns[i],
sortable: false
}
break;
case 'columnname2':
visible = false;
colObj = {
field: columns[i],
sortable: false
}
break;
default:
break;
}
if (visible) {
if (colObj != undefined)
this.gridcolumnDefs.push(colObj);
}
}
// set column grid
this.GridName.setColumnDefs(this.gridcolumnDefs)
please try and check.
I have a Apex method which returns the list of wrapper class as JSON string
having LWC js controller to call the method in connnectedCallback() and the wrapper list is assigned to a property this.coreAttributes which is show in html page using basic html tags along with other property defined in LWC noOfBlocks, faltHierarchy, and one more. code given below.
When I enter some value in coreAttribute's related input filed and enter some value in noOfBlocks input field, the value entered in the coreAttribute related fields are gone. please check the attached gif and help me to resolve this.
Image : https://easyupload.io/g1h772
#AuraEnabled(cacheable=true)
public static String queryCoreAttributes() {
List<Core_Attribute__c> coreAttributesList = new List<Core_Attribute__c>();
Map<Id,List<String>> picklistValuesToPicklistMasterMap = new Map<Id,List<String>>();
coreAttributesList = [SELECT Id, Name, Data_Type__c, Type__c, Picklist_Master__c
FROM Core_Attribute__c WHERE Base_Asset_Name__c IN (SELECT Id FROM Base_Asset_Template__c WHERE Name = 'Base PV Plant')
ORDER BY Name ASC];
picklistValuesToPicklistMasterMap = Utils.getPicklistValues();
System.debug(' picklistValuesToPicklistMasterMap '+ picklistValuesToPicklistMasterMap);
List<coreAttributesWrapper> coreAttributesWrapperList = new List<coreAttributesWrapper>();
for(Core_Attribute__c coreAttribute : coreAttributesList){
coreAttributesWrapper coreAttWrapper = new coreAttributesWrapper();
coreAttWrapper.attributeHeader = coreAttribute.Name;
coreAttWrapper.attributeDataType = coreAttribute.Data_Type__c.toLowerCase();
coreAttWrapper.picklistValues = (coreAttribute.Data_Type__c == 'Picklist') ? picklistValuesToPicklistMasterMap.get(coreAttribute.Picklist_Master__c): null;
coreAttWrapper.isPicklist = (coreAttribute.Data_Type__c == 'Picklist');
coreAttWrapper.attributeValue = '';
coreAttributesWrapperList.add(coreAttWrapper);
}
System.debug(' core Att '+ coreAttributesWrapperList);
return JSON.serialize(coreAttributesWrapperList);
}
JS
import { LightningElement, track, api } from "lwc";
import getPlantAssetRecord from "#salesforce/apex/P1PlantInfoPromptSolar.queryPlantAssetRecord";
import queryCoreAttributes from "#salesforce/apex/P1PlantInfoPromptSolar.queryCoreAttributes";
import saveP1PlantInfoPromptMetadata from "#salesforce/apex/P1PlantInfoPromptSolar.saveP1PlantInfoPromptMetadata";
export default class P1PlantInfoPromptSolar extends LightningElement {
#api plantAssetId='';
#track plantAssetDetail;
#track coreAttributes;
#track noOfBlocks='';
#track flatHierarchy=false;
#track drivePlus=false;
#track promptSpecificAttributes;
connectedCallback() {
console.log(' connected callback ');
getPlantAssetRecord({
recordId: 'a060p000001hGLxAAM',
})
.then(result => {
this.plantAssetDetail = result;
})
.catch(error => {
this.error = error;
});
queryCoreAttributes()
.then(result => {
console.log(' result ' + result);
console.log(' JSON result ' + JSON.parse(result));
this.coreAttributes = JSON.parse(result);
})
.catch(error => {
this.error = error;
});
}
inputTagValueChangeHandler(event){
console.log(' test '+ JSON.stringify(this.coreAttributes));
console.log(' value -> '+ event.target.value + ' name -> ' + event.target.name);
if(event.target.name === 'Blocks') this.noOfBlocks = event.target.value;
if(event.target.name === 'Flat Hierarchy') this.flatHierarchy = event.target.value;
if(event.target.name === 'Drive+') this.drivePlus = event.target.value;
}
HTML
<tr data-row="1">
<th># Blocks</th>
<td><input type="number" name="Blocks"
value={noOfBlocks} onchange={inputTagValueChangeHandler}/></td>
</tr>
<tr data-row="2">
<th>Flat Hierarchy</th>
<td><input type="checkbox" name="Flat Hierarchy"
value={flatHierarchy} onchange={inputTagValueChangeHandler}/></td>
</tr>
<tr data-row="2">
<th>Drive+</th>
<td><input type="checkbox" name="Drive+"
value={drivePlus} onchange={inputTagValueChangeHandler}/></td>
</tr>
<template for:each={coreAttributes} for:item="coreAttribute">
<tr key={coreAttribute.key}>
<th>{coreAttribute.attributeHeader}</th>
<td>
<template if:false={coreAttribute.isPicklist}>
<input type={coreAttribute.attributeDataType} name={coreAttribute.attributeHeader}
value={coreAttribute.attributeValue}/>
</template>
<template if:true={coreAttribute.isPicklist}>
<select size="1" name={coreAttribute.attributeHeader}>
<option value="None">--None--</option>
<template for:each={coreAttribute.picklistValues} for:item="attributePickValues">
<option key={coreAttribute.key} value={coreAttribute.attributeValue}>{attributePickValues}</option>
</template>
</select>
</template>
</td>
</tr>
</template>
I have an model in which I have a method is valid
export class ModelClass{
id: number;
text : String,
isValid() : boolean {
return true;
}
}
a second model
export class Rows{
editable: boolean;
modelClass: ModelClass;
}
how to call it in html ???
<table border="1p;">
<tbody >
<tr *ngFor="let link of modelClassRows">
<td>
<div>toto {{link.applicationLink.isValid()}}</div>
</td>
</tr>
</tbody>
</table>
a part of my component where object are initialized
export class ApplicationLinkListComponent implements OnInit {
modelClassRows: Rows[] = new Array<Rows>();
constructor() {
}
ngOnInit() {
// fill modelClassRows
.....
}
You need to instantiate the ModelClass class this way:
let row = new Rows();
row.modelClass = new ModelClass();
row.modelClass.id = 'some id';
row.modelClass.title = 'some title';
modelClassRows.push(row);
If you instantiate it literally and cast it to the type, you won't be able to use the method.
For example:
let row = new Rows();
row.modelClass = <ModelClass>{
id: 'some id',
title: 'some title'
};
modelClassRows.push(row);
I'm using this video-example (https://www.youtube.com/watch?v=FZSjvWtUxYk) in order to make an errors reporting app. The problem comes when in the View when it passes the object that comes from the REST-AJAX call, _.template says that errores is not defined.
Here is my code:
var Error = Backbone.Model.extend({
defaults: {
iderror: '',
title: '',
url: ''
},
idAttribute: 'iderror'
});
var Errores = Backbone.Collection.extend({
model: Error,
url: '/errores'
});
var ErrorList = Backbone.View.extend({
el: '.page',
render: function (eventName) {
var that = this;
var errores = new Errores();
errores.fetch({
success: function (errores) {
var template = _.template($('#error-list-template').html(),{errores: errores.models});
that.$el.html(template);
}
});
}
});
My Template code:
<script type="text/template" id="error-list-template">
Registrar Error
<hr/>
<table class="table striped">
<thead>
<tr>
<th>Id Error</th>
<th>TÃtulo</th>
<th>URL</th>
<th></th>
</tr>
</thead>
<tbody>
<%
_.each(errores, function(error) { %>
<tr>
<td><%= error.get('iderror') %></td>
<td><%= error.get('title') %></td>
<td><%= error.get('url') %></td>
<td>Editar</td>
</tr>
<% }); %>
</tbody>
</table>
</script>
My RESTful GET function made with SLIM Framework:
$app->get('/errores/', function () {
//echo "Hello, ";
$datos = array();
$db = NewADOConnection('mysqli');
$db->Connect("localhost", "root", "mypassword", "tt1r");
$sql = "SELECT * FROM tt1r.course";
$qry = $db->execute($sql);
/*while (!$qry->EOF) {
//print_r($qry->fields);
$datos = [$qry->iderror => ['title' => $qry->title, 'url' => $qry->url]];
$qry->MoveNext();
}*/
if($qry) {
foreach($qry as $re){
//return $re['ADM_ID'];
$datos[] = array("iderror" => $re['iderror'],"title" => $re['title'],"url" => $re['url']);
}
$db = null;
//echo json_encode($datos);
//echo '{"user": ' . json_encode($datos) . '}';
echo json_encode($datos);
}
});
I have to say that I do get the JSON array with the data from the RESTful function, but it doesn't show it.
Thank you for your help.
Best regards.
Rafa
I read the answer in a post made by RyanP13.
So the fixed View code is:
var ErrorList = Backbone.View.extend({
el: '.page',
render: function () {
var that = this;
var errores = new Errores();
errores.fetch({
success: function(errores, response, options){
var template = _.template($('#error-list-template').html());
that.$el.html(template({ errores: errores.toJSON()}));
}
});
}
});
The problem was that I did not had any reference from the Collection.
Hope this help you as well.
Best regards
Rafa
I having difficulty where the Kendo Ui grid would not rebind with new result after the Search button click.Please let me know how i could achieve this. Thank you
Currently the GetList will return data correctly however the KendoUi grid would not rebind with the new result.
.cshtml
<div id="search">
<div>
<div class="searchOption">
#Html.LabelFor(model => model.HRN)
#Html.EditorFor(model => model.HRN)
</div>
</div>
<div>
<div class="smallBox">
<input type="button" id="btnSearch" style="height:32px; font-size:14px; background-color:#3399FF" class="k-button" title="Search" value="Search" />
</div>
</div>
<div>
<div class="searchOption">
#Html.LabelFor(model => model.FamilyName)
#Html.EditorFor(model => model.FamilyName)
</div>
</div>
<div>
<div class="searchOption">
#Html.LabelFor(model => model.GivenName)
#Html.EditorFor(model => model.GivenName)
</div>
</div>
<div>
<div class="searchOption">
#Html.LabelFor(model => model.Priority)
#Html.EditorFor(model => model.Priority)
</div>
</div>
</div>
#(Html.Kendo().Grid<PWeb_App.ViewModels.ResultModel>()
.Name("Result")
.HtmlAttributes(new { #Style = "align:center; font-size:10px; width:985px" })
.Events(ev => ev.Change("onChange"))
.Columns(columns =>
{
columns.Bound(p => p.GivenName).Width(90);
columns.Bound(p => p.FamilyName).Width(90);
columns.Bound(p => p.Community).Width(130);
})
.ToolBar(toolbar => toolbar.Save())
.Editable(editable => editable.Mode(GridEditMode.InCell))
.Sortable()
.Pageable(paging => paging
.Input(false)
.Numeric(true)
.PreviousNext(true)
.PageSizes(new int[] { 5, 10, 25, 50 })
.Refresh(false)
)
.Selectable()
.Scrollable()
.ColumnMenu(c => c.Columns(false))
.DataSource(dataSource => dataSource
.Ajax()//bind with Ajax instead server bind
.PageSize(10)
.ServerOperation(true)
.Model(model =>
{
model.Id(p => p.Pid);
model.Field(p => p.FamilyName).Editable(false);
model.Field(p => p.GivenName).Editable(false);
})
.Read(read => read.Action("GetData", "Details").Type(HttpVerbs.Get))
.Update("Edit", "Details")
)
)
<script type="text/javascript">
$(document).ready(function () {
$('#btnConsumerSearch').click(function (e){
var community = $("#Community").val();
var familyName = $("#FamilyName").val();
var givenName = $("#GivenName").val();
$.ajax({
type: 'POST',
complete: function(e) {
$("#Result").data("kendoGrid").dataSource.read();
},
url: "#(Url.Content("~/Details/GetData/"))",
data: {
"Community":community,
"FamilyName":familyName,
"GivenName":givenName
},
success: function () {
$("#btnSearch").removeAttr('disabled');
}
});
$("#btnSearch").attr('disabled','disabled');
});
});
</script>
controller:
//The following code will return data new result as expected however the kendo grid does not refresh with the result of the following code:
public ActionResult GetData([DataSourceRequest] DataSourceRequest request, SearchCriteria model)
{
DataTable result = GetList(model);
Response.Cache.SetCacheability(HttpCacheability.NoCache);
return Json(result.ToDataSourceResult(request), JsonRequestBehavior.AllowGet);
}
/// <summary>
/// Get all available List from Client table and return using datatable
/// </summary>
/// <returns></returns>
private DataTable GetList(SearchCriteria model, string ReferralListID)
{
using (PEntities context = new PEntities())
{
string ConnectionString = (context.Connection as EntityConnection).StoreConnection.ConnectionString;
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(ConnectionString);
builder.ConnectTimeout = 2500;
using (SqlConnection con = new SqlConnection(builder.ConnectionString))
{
using (SqlDataAdapter adapter = new SqlDataAdapter())
{
using (SqlCommand cmd = new SqlCommand("spListResults", con))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("paramCommunity", SqlDbType.VarChar, 100).Value = !String.IsNullOrEmpty(model.Community) ? (object)model.Community : DBNull.Value;
cmd.Parameters.Add("paramGivenName", SqlDbType.VarChar, 100).Value = !String.IsNullOrEmpty(model.GivenName) ? (object)model.GivenName : DBNull.Value;
cmd.Parameters.Add("paramFamilyName", SqlDbType.VarChar, 100).Value = !String.IsNullOrEmpty(model.FamilyName) ? (object)model.FamilyName : DBNull.Value;
cmd.Parameters.Add("paramPriority", SqlDbType.VarChar, 10).Value = !String.IsNullOrEmpty(model.Priority) ? (object)model.Priority : DBNull.Value;
adapter.SelectCommand = cmd;
cmd.CommandTimeout = 0;
DataTable dt = new DataTable();
adapter.Fill(dt);
return dt;
}
}
}
}
}
Try like this,
In your grid read method in view like this
.Read(read => read.Action("GetData", "Details").Data("GetData"))
You button should be Submit Type
<input type="Submit" id="btnSearch" style="height:32px; font-size:14px; background-color:#3399FF" class="k-button" title="Search" value="Search" />
Script
function GetData() {
return {
HRN: $('#HRN').val(),
FamilyName: $('#FamilyName').val(),
GivenName: $('#GivenName').val(),
Priority: $('#Priority').val()
};
}
$(document).ready(function () {
$("#btnSearch").click(function (e) {
$("#Result").data("kendoGrid").dataSource.read();
$("#Result").data("kendoGrid").refresh();
e.preventDefault();
});
});
Controller
public ActionResult GetData([DataSourceRequest] DataSourceRequest request, string HRN, string FamilyName, string GivenName, string Priority)
{
DataTable result = GetList(HRN,FamilyName,GivenName,Priority);
Response.Cache.SetCacheability(HttpCacheability.NoCache);
return Json(result.ToDataSourceResult(request), JsonRequestBehavior.AllowGet);
}