I would like to disable column on databound based on the role security.
I am currently able to hide it not disable as the following but i have no idea how to disable it. Please advise thank you
function OnDataBound_ProductGrid() {
if ("#ViewBag.Role" == 'Admin') {
var grid = $("#Product").data("kendoGrid");
grid.hideColumn(0);
}
}
#(Html.Kendo().Grid(Model)
.Name("Grid")
.Columns(columns =>
{
columns.Template(ClientTemplate("<input type='checkbox' class='checkbox'/> ");
columns.Bound(r => r.RouteName);
})
.Events(events =>ev.DataBouns("OnDataBound_ProductGrid"))
)
I agree with Antony:
Following property must be set to false:
model: {
fields: {
ProductID: {
//this field will not be editable (default value is true)
editable: false
}
}
}
And in your scenario you should be able to do following:
function OnDataBound_ProductGrid() {
if ("#ViewBag.Role" == 'Admin') {
var grid = $("#Product").data("kendoGrid");
grid.datasource.fields.ProductId.editable = false;
}
}
Wrapping/using the admin role condition around the grid definition would also do the job:
if ("#ViewBag.Role" == 'Admin') {
InnitGrid(false);
}
else
{
InnitGrid(true);
}
function InnitGrid(isEditable) {
$("#grid").kendoGrid({
dataSource: {
model: {
fields: {
ProductID: {
editable: isEditable
// or just replace isEditable with ("#ViewBag.Role" == 'Admin')
}
}
}
}
});
}
You can do this by setting the field to editable: false on the data source.
You can use a function that returns true or false, in depends what do you need.
columns.Bound(r => r.RouteName).Editable("isNotEditable");
function isNotEditable() {
return false;
}
Related
In my project I use ng2-charts. All works fine and chart is shown as expected (data, labels, chart's colors), but when data is changed then color of chart become grey by default. May someone help to correct problem with chart's color?
Here is my code:
import { ChartDataSets } from 'chart.js';
import { Color, Label } from 'ng2-charts';
...
export class JuridicalBidPrimaryComponent extends BidComponent {
lineChartData: ChartDataSets[];
lineChartLabels: Label[];
lineChartLegend = true;
lineChartType = 'line';
lineChartColors: Color[] = [
{
backgroundColor: 'rgba(148,159,177,0.2)',
borderColor: 'rgba(148,159,177,1)'
},
{
backgroundColor: 'rgba(77,83,96,0.2)',
borderColor: 'rgba(77,83,96,1)'
}];
options: any = {
legend: { position: 'bottom' }
}
constructor(
...//inject services
) {
super();
this.initData();
};
initData(): void {
this.lineChartData = [];
this.lineChartLabels = [];
if (this.cabinetId)
this.getData(this.year);
}
getData(year: number) {
this.isLoading = true;
var limitPromise = this.juridicalLimitService.getPrimary(this.cabinetId, year).catch(error => {
this.notificationService.error(error);
return Observable.throw(error);
});
var analyticsPromise = this.juridicalAnalyticsService.getUsedEnergy(this.cabinetId, year).catch(error => {
this.notificationService.error(error);
return Observable.throw(error);
});
forkJoin([limitPromise, analyticsPromise]).subscribe(data => {
this.limits = data[0];
this.lineChartLabels = data[1].map(e => e.Period);
this.lineChartData.push(
{
data: data[1].map(e => e.Limit),
label: 'Bid'
},
{
data: data[1].map(e => e.Used),
label: 'Used'
}
);
this.isLoading = false;
}, error => {
this.isLoading = false;
});
}
}
export abstract class BidComponent {
cabinetId: number;
isLoading: boolean = false;
#Input("periods") periods: BaseDictionary[];
#Input("cabinetId") set CabinetId(cabinetId: number) {
this.cabinetId = cabinetId;
this.initData();
}
abstract initData(): void;
}
As you can see this component is partial and I use setter to listen of cabinetId changes.
Here is html part:
...
<canvas baseChart width="400" height="150"
[options]="options"
[datasets]="lineChartData"
[labels]="lineChartLabels"
[legend]="lineChartLegend"
[chartType]="lineChartType"
[colors]="lineChartColors"></canvas>
...
And I use this component as:
<app-juridical-bid-primary [cabinetId]="cabinetId"></app-juridical-bid-primary>
I find similar question similar question, but, unfortunately, don't understand answer
After some hours of code testing I find answer. It is needed to correct code from question:
...
import * as _ from 'lodash'; //-- useful library
export class JuridicalBidPrimaryComponent extends BidComponent {
lineChartData: ChartDataSets[] = [];
lineChartLabels: Label[] = [];
...
initData(): void {
/*this.lineChartData = [];
this.lineChartLabels = [];*/ //-- this lines is needed to remove
if (this.cabinetId)
this.getData(this.year);
}
getData(year: number) {
...
forkJoin([limitPromise, analyticsPromise]).subscribe(data => {
this.limits = data[0];
this.lineChartLabels.length = 0;
this.lineChartLabels.push(...data[1].map(e => e.Period));
if (_.isEmpty(this.lineChartData)) {
//-- If data array is empty, then we add data series
this.lineChartData.push(
{
data: data[1].map(e => e.Limit),
label: 'Замовлені величини'
},
{
data: data[1].map(e => e.Used),
label: 'Використано'
}
);
} else {
//-- If we have already added data series then we only change data in data series
this.lineChartData[0].data = data[1].map(e => e.Limit);
this.lineChartData[1].data = data[1].map(e => e.Used);
}
this.isLoading = false;
}, error => {
this.isLoading = false;
});
}
}
As I understand ng2-charts, if we clean dataset (lineChartData) and add new data then the library understand this as create new series and don't use primary settings for the ones. So we have to use previous created series.
I hope it will be useful for anyone who will have such problem as I have.
I got the following input text on a Child Component:
<Input
placeholder={ i18n.t('searchSomeone') }
value={ this.props.searchText }
onChangeText={ this.props.onSearch }
defaultValue={''}/>
This is the way , I'm passing the variable and onChangeText handler:
<ChildComponent
onSearch={ this._onSearch }
searchText={ this.state.searchText }>
</ChildComponent>
And this is the _onSearch() function:
componentWillMount: function() {
this._onSearch = _.debounce((text) => {
this.setState({ refreshing : true }, () => {
if(text.length === 0) {
this.setState({ filteredSearch: false }, () => {
this.getAllReports();
})
}else{
this.setState({
page: 1,
refreshing: true,
reports: [],
filteredSearch: true
}, () => {
this.getReportsBySearchString();
})
}
})
}, 1000);
},
I wanted to bind this input text value, because when I do a pull up to refresh, i just want to set the text to empty string.
_onRefresh: function() {
this.setState({
filteredSearch: false,
searchText: ''
}, () => {
this.getAllReports();
})
},
But the problem is that with this implementation, whenever I try to type in the text input, it doesn't type anything.
What am I missing?
It looks like you are not saving the input value in this.state.searchText. That's the reason why the input value is always ''.
this._onSearch = _.debounce((text) => {
this.setState({
refreshing : true,
searchText: text // <-- Here
}, () => {
if(text.length === 0) {
this.setState({ filteredSearch: false }, () => {
this.getAllReports();
})
}else{
this.setState({
page: 1,
refreshing: true,
reports: [],
filteredSearch: true
}, () => {
this.getReportsBySearchString();
})
}
})
}, 1000);
Edit
You can try debounce the callback function you are passing to setState, it is not tested so I'm not sure if it is going to work.
It should be something like this
this._onSearch = (text) => {
this.setState({
refreshing : true,
searchText: text
}, this._callback)
this._callback = _.debounce(() => {
const text = this.state.searchText;
if(text.length === 0) {
...
}
}, 1000);
I have a page where a bunch of file ids get loaded from localStorage, then when the component mounts / receives new props, it calls setVariables. While this works and the new variables are set, the results from the initial variables is used during the transition, which causes an odd flickering result.
Why would Relay give me something different during the transition at all? My expectation would be that this.props.viewer.files.hits would be the same as the previous call while setVariables is doing its thing, not the result from using the initial variables.
const enhance = compose(
lifecycle({
componentDidMount() {
const { files, relay } = this.props
if (files.length) {
relay.setVariables(getCartFilterVariables(files))
}
},
}),
shouldUpdate((props, nextProps) => {
if (props.files.length !== nextProps.files.length && nextProps.files.length) {
props.relay.setVariables(getCartFilterVariables(nextProps.files))
}
return true
})
)
export { CartPage }
export default Relay.createContainer(
connect(state => state.cart)(enhance(CartPage)), {
initialVariables: {
first: 20,
offset: 0,
filters: {},
getFiles: false,
sort: '',
},
fragments: {
viewer: () => Relay.QL`
fragment on Root {
summary {
aggregations(filters: $filters) {
project__project_id {
buckets {
case_count
doc_count
file_size
key
}
}
fs { value }
}
}
files {
hits(first: $first, offset: $offset, filters: $filters, sort: $sort) {
${FileTable.getFragment('hits')}
}
}
}
`,
},
}
)
Ah I finally figured this out. prepareParams was changing the value
export const prepareViewerParams = (params, { location: { query } }) => ({
offset: parseIntParam(query.offset, 0),
first: parseIntParam(query.first, 20),
filters: parseJsonParam(query.filters, null), <-- setting filters variable
sort: query.sort || '',
})
const CartRoute = h(Route, {
path: '/cart',
component: CartPage,
prepareParams: prepareViewerParams, <--updating variable
queries: viewerQuery,
})
For example, I bind the resource as follows.
.Resources(resource =>
{
resource.Add(m => m.UserName)
.Title("Staff")
.Name("Staff")
.DataTextField("Text")
.DataValueField("Value")
.DataSource(source => source
.Read(read => read.Action("GetStaffList", "Scheduler"))
);
})
When the editor popups, the staff input has type of dropdown list which contains all the Staff in database.
Question: How to change it to an autocomplete widget with server filtering by staff's name for example.
Thank you.
I would jump into JavaScript by hooking up a event on edit to the grid, then you can do it there doing something like this
function onEdit(e) {
//Autocompleter
$("#Staff").kendoAutoComplete({
dataSource: {
serverFiltering: true,
transport: {
read: { url: "/Staff/GetListForAutocompleter" },
parameterMap: function (data, action) {
var newParams = { filter: $("#Staff").val(), filter2: 'something' };
return newParams;
}
}
}
});
}
In the edit Form is a select dropdown. When the user select an item, i want to load some values and fill them into the form.
My code so far:
var grid = $("#list").jqGrid({
parameters...,
colNames:[...],
colModel :[
...
]
});
$("#list").jqGrid(
'navGrid',
'#pager',
{
view:true,
edit:true,
del:true,
search:false,
},
/* EDIT */
{
closeAfterEdit: true,
afterSubmit: processAddEdit,
onInitializeForm: setFormEvents,
...
}
...
);
function setFormEvents(formid) {
/* It sometim works when using timeout..
* It seems to be a timing issue.
* But i have no idea why and how to solve
*/
setTimeout ( function(){
$('select#data_id', formid).unbind();
$('select#data_id', formid).change(function() {
$.getJSON("/URL?dataid=" + $('select#data_id option:selected').val(),
function(data){
$.each(data, function(i,item){
if (item.field == "anrede") { $("#anrede").val(item.value); }
else if (item.field == "titel") { $("#titel").val(item.value); }
else if (item.field == "vorname") { $("#vorname").val(item.value); }
else if (item.field == "nachname") { $("#nachname").val(item.value); }
else if (item.field == "firma") { $("#firma").val(item.value); }
else if (item.field == "strasse") { $("#strasse").val(item.value); }
else if (item.field == "hausnummer") { $("#hausnummer").val(item.value); }
else if (item.field == "plz") { $("#plz").val(item.value); }
else if (item.field == "ort") { $("#ort").val(item.value); }
else if (item.field == "land") { $("#land").val(item.value); }
});
});
});
}, 1000 );
}
To bind event (like change event in your case) to the edit field you should use dataEvents of the editoptions. See here, here or here examples. Moreover I recommend you to use recreateForm:true option additionally.