I have a slickgrid cell with an autocompletion and a custom formatter. The cell value is a key field of dynamically loading autocompletion list. The list is shown as labels (e.g. Contract: ABCDEF-123, thick:10, width:210, City: Chicago) and when I select one it appears in the according input field. The point is that the formatter does not know that label, it only knows the key (order_id).
function contractFormatter(row, cell, value, columnDef, dataContext) {
var res = '';
var val = get_contract_list()[value] ? get_contract_list()[value]['label'] : '';
res = '<span class="' + getSpanClass() + '" style="float: left;"></span>\n\
'+ (val =='' ? '<span style="color:slategrey;"> Enter 3 symbols </span>' + val : val) + '';
return res;
}
The function get_contract_list returns the whole list of contracts and it is very big, so it was decided to make that list dynamic. So the function is empty now and it would be nice just to take the selected label into val.
Is there any way to achieve it?
You have to remember that Formatters are synchronous and it must return right away in a string format, if it requires a lot of processing power while staying synchronous then you'll end up slowing down your grid. You should probably cache your list once in a separate variable and use it afterward instead of reloading the list every time. If you load something that takes time and is asynchronous (a delayed output) then you'll want to look up the asyncPostRenderer (you can see this Example)
So going back to displaying the associated key to a label, I've done something similar in my lib in this Example and a live demo here, in my use case the value is a key index and I use the complexityLevelList to find its associated object which I can then read its label to display in the formatter.
export class MyExample {
complexityLevelList = [
{ value: 0, label: 'Very Simple' },
{ value: 1, label: 'Simple' },
{ value: 2, label: 'Straightforward' },
{ value: 3, label: 'Complex' },
{ value: 4, label: 'Very Complex' },
];
prepareGrid() {
this.columnDefinitions = [
{
id: 'complexity', name: 'Complexity', field: 'complexity', minWidth: 100,
formatter: (_row, _cell, value) => this.complexityLevelList[value].label,
filter: {
model: Filters.multipleSelect,
collection: this.complexityLevelList
},
editor: {
model: Editors.singleSelect,
collection: this.complexityLevelList,
massUpdate: true
},
},
];
}
}
Note that the Filters & Editors are specific to my lib Slickgrid-Universal, but you should get the idea on how to refactor your code to make it work.
Related
I have a list of options for multi-select. in one of the option I should add another field-remark field. so selecting in the first time add this field. but when removing the selection it does not removing this selection from the array becouse I did not remove the remark field. so when select this option again will add twice the same index(one with the remark field and one with null in the remark) I need to set value only if I dont have this index in the array
<p-multiSelect [required]="formGroup.hasError('remark-reasons-required')"
[options]="reasons" defaultLabel="" formControlName="remarks" optionLabel="hebName"
selectedItemsLabel="{0} "
(onChange)="onChangeReasonsValue($event)"></p-multiSelect>
onChangeReasonsValue(event: { value: ReviewDecisionReasonModel[] }): void {
//
var selectedArray = event.value.filter(function (item, pos) {
return event.value.indexOf(item) == pos;
})
this.formGroup.get('remarks').setValue(selectedArray);
this.selectedReasons = selectedArray;
this._decision.reasons = selectedArray;
}
It seems the multi-select component have a bug, where the disabled/removed options from the component remain added to the related formControl.
I propose you add a "disabled" property to your options, and set this option as the selections change instead of adding/removing them. After that, you could adjust the formValues with only enabled options.
Also, you could not use (OnChange) in favor of subscribing to the form changes from the component.
something like
otherReasonWhen2 = { id: 3, hebName: 'heb3', freeTextAllow: false, disabled: true };
reasons = [
{ id: 1, hebName: 'heb1', freeTextAllow: false, disabled: false },
{ id: 2, hebName: 'heb2', freeTextAllow: false, disabled: false },
this.otherReasonWhen2,
];
ngOnInit() {
this.formGroup.get('remarks').valueChanges.subscribe((newValues) => {
console.log(newValues) // This is here for you to see the values as they change
this.otherReasonWhen2.disabled = newValues.every(reason => reason.id !== 2)
if (newValues.some(reason => reason.disabled)){
// work-around for the observed bug: when there are disabled options selected, remove them from the form.
this.formGroup.get('remarks').setValue(newValues.filter(reason => !reason.disabled));
}
});
}
and don't forget to add the directive to disabled the option:
<p-multiSelect
[options]="reasons"
optionDisabled="disabled" <-- Here
defaultLabel=""
formControlName="remarks"
optionLabel="hebName"
selectedItemsLabel="{0} "
></p-multiSelect>
I am using ag-Grid table in a Reactjs app, a snippet of my code can be seen below:
const columnsDef = [
.
.
{
headerName: 'Side',
field: UI_FIELDS.SIDE,
width: 70,
cellRenderer: sideRenderer,
cellRendererParams: {
value: "BUY"
}
},
.
.
]
function sideRenderer(params) {
const value = _.get(params, 'value') || '';
const styleSuffix = _.isEmpty(value) ? 'default' : value.toLowerCase();
return `<span class="side-renderer side-renderer-${styleSuffix}">${value}</span>`;
}
I have hardcoded value: "BUY" in my cellRendererParams for the moment, but I want this to actually be equal to whatever is in that cell for that column, which could be either BUY or SELL.
This value affects what css is applied to the text, a BUY value will be coloured Green and a Sell value will be colour Red.
How do I set value to be equal to the actual text in the cell and not be hard coded like this?
You can do something like this
const columnsDef = [
{
headerName: 'Side',
field: UI_FIELDS.SIDE,
width: 70,
cellRenderer: (params) => params.value.toLowerCase() === 'buy' ? `<span class="side-renderer side-renderer-buy">${params.value}</span>` : `<span class="side-renderer side-renderer-sell">${params.value}</span>
}
]
I guess this is what you want? If not please explain in more details what you need.
Edit: You do not really need to pass the cell renders params, you can get the cell's value using params.value
Thanks 'A Ghanima' for mentioning to use params.value, this helped me come up with the following solution which works
{
headerName: 'Side',
field: UI_FIELDS.SIDE,
width: 70,
cellRenderer: sideRenderer,
cellRendererParams: (params) => { value: params.value }
}
Although I've specified text and hoverinfo, I'm not getting any hover annotation at all.
If I comment out the "text" attribute, I get the default behavior of hoverinfo: "x+y". I've also tried hoverinfo: "text" and hoverinfo: "x+text" (which is what I really want), but these do not change the behavior.
https://jsfiddle.net/abalter/0cjprqgy/
var data =
{
"x":["2014-02-10 00:00:00.0","2014-02-18 00:00:00.0","2014-02-24 00:00:00.0"],
"y":[0,0,0],
"text":["gemcitabine","gemcitabine + Abraxane","Xeloda"],
"hoverinfo": "all",
"name":"Treatment",
"type":"scatter",
"mode":"markers",
"marker":
{
"size":9,
"color":"#800000"
},
"uid":"c2e171"
};
var layout =
{
"title":"Treatments",
"height":600,
"width":655,
"autosize":true,
"yaxis":
{
"titlefont":
{
"size":12,
"color":"#800000"
},
"domain":[0.85,0.9],
"showgrid":false,
"showline":false,
"showticklabels":false,
"zeroline":true,
"type":"linear",
"range":[0,0],
"autorange":true
},
"hovermode":"closest",
"xaxis":
{
"type":"date",
"range":[1389215256994.8186,1434909143005.1814],
"autorange":true
}
};
Plotly.plot('graph', [data], layout);
First of all, thank you for having me to discover this really cool graphic platform! I checked at the documentation to get to know how the data has to be formatted (here: https://plot.ly/javascript/hover-events/#coupled-hover-events-on-single-plot)... And "played" with you fiddle.
First, I removed all the unnessessary double quotes you had there, wrapping the param names and placed your value arrays outside of the "data" array. I don't know if it is part of the problem... I just tryed to format it as the example I found.
The "x+y+text" suddenly appeared when I played with the "domain" parameter.
I don't know what it really defines.
I repeat, I have a 10 minutes experience with this thing. (lol)
Check this update I made of your fiddle : https://jsfiddle.net/0cjprqgy/6/
var dates = ["2014-02-10 00:00:00.0","2014-02-18 00:00:00.0","2014-02-24 00:00:00.0"],
qty = ["0.2","0.5","1"],
product = ["gemcitabine","gemcitabine + Abraxane","Xeloda"],
data =
{
x:dates,
y:qty,
text:product,
hoverinfo: "x+y+text",
name:"Treatment",
type:"scatter",
mode:"markers",
marker:
{
size:9,
color:"#800000"
},
uid:"c2e171"
};
var layout =
{
title:"Treatments",
height:600,
width:655,
autosize:true,
yaxis:
{
titlefont:
{
size:12,
color:"#800000"
},
domain:[0.85,1.9],
showgrid:false,
showline:false,
showticklabels:false,
zeroline:true,
type:"linear",
range:[0,0],
autorange:true
},
hovermode:"closest",
xaxis:
{
type:"date",
range:[1389215256994.8186,1434909143005.1814],
autorange:true
}
};
Plotly.plot('graph', [data], layout);
Once a grid is rendered how can I set focus to the first item. I am running into a problem where when the grid is updated (collection changes) then focus is lost for the entire application .
I am using the moonstone library.
{
kind: "ameba.DataGridList", name: "gridList", fit: true, spacing: 20, minWidth: 300, minHeight: 270, spotlight : 'container',
scrollerOptions:
{
kind: "moon.Scroller", vertical:"scroll", horizontal: "hidden", spotlightPagingControls: true
},
components: [
{kind : "custom.GridItemControl", spotlight: true}
]
}
hightlight() is a private method for Spotlight which only adds the spotlight class but does not do the rest of the Spotlight plumbing. spot() is the method you should be using which calls highlight() internally.
#ruben-ray-vreeken is correct that DataList defers rendering. The easiest way to spot the first control is to set initialFocusIndex provided by moon.DataListSpotlightSupport.
http://jsfiddle.net/dcw7rr7r/1/
enyo.kind({
name: 'ex.App',
classes: 'moon',
bindings: [
{from: ".collection", to: ".$.gridList.collection"}
],
components: [
{name: 'gridList', kind:"moon.DataGridList", classes: 'enyo-fit', initialFocusIndex: 0, components: [
{kind:"moon.CheckboxItem", bindings: [
{from:".model.text", to:".content"},
{from:".model.selected", to: ".checked", oneWay: false}
]}
]}
],
create: enyo.inherit(function (sup) {
return function () {
sup.apply(this, arguments);
// here, at least, the app starts in pointer mode so spotting the first control
// isn't apparent (though it would resume from that control upon 5-way action).
// Turning off pointer mode does the trick.
enyo.Spotlight.setPointerMode(false);
this.set("collection", new enyo.Collection(this.generateRecords()));
};
}),
generateRecords: function () {
var records = [],
idx = this.modelIndex || 0;
for (; records.length < 20; ++idx) {
var title = (idx % 8 === 0) ? " with long title" : "";
var subTitle = (idx % 8 === 0) ? "Lorem ipsum dolor sit amet" : "Subtitle";
records.push({
selected: false,
text: "Item " + idx + title,
subText: subTitle,
url: "http://placehold.it/300x300/" + Math.floor(Math.random()*0x1000000).toString(16) + "/ffffff&text=Image " + idx
});
}
// update our internal index so it will always generate unique values
this.modelIndex = idx;
return records;
},
});
new ex.App().renderInto(document.body);
Just guessing here as I don't use Moonstone, but the plain enyo.Datalist doesn't actually render its list content when the render method is called. Instead the actual rendering task is deferred and executed at a later point by the gridList's delegate.
You might want to dive into the code of the gridList's delegate and check out how it works. You could probably create a custom delegate (by extending the original) and highlight the first child in the reset and/or refresh methods:
enyo.Spotlight.highlight(this.$.gridList.childForIndex(0));
Ruben's answer adds on to my answer that I posted in the Enyo forums, which I'm including here for the sake of completeness:
Try using
enyo.Spotlight.highlight(this.$.gridList.childForIndex(0));
I added a rendered() function to the Moonstone DataGridList sample in the Sampler and I found that this works:
rendered: function() {
this.inherited(arguments);
this.startJob("waitforit", function() {
enyo.Spotlight.highlight(this.$.gridList.childForIndex(0));
}, 400);
},
It didn't work without the delay.
Issue
I just started using Select2 (http://ivaynberg.github.io/select2/) and I am trying to do a basic task.
I have a select box that has, for example, 3 items in it. I want to be able to have the user either select 1 of the 3 results or type in their own result and then eventually, on submit, it will submit whatever value is in the box.
What I've Tried
<input style="width: 200px;" type="hidden" id="foo" />
<script type="text/javascript">
$(document).ready(function () {
$("#foo").select2({
query: function (query) {
var data = { results: [{ text: 'math' }, { text: 'science' }, { text: 'english' }] };
data.results.push({ text: query.term });
query.callback(data);
}
});
});
</script>
The code above allows me to see the 3 results and type in a result myself. But I am unable to get the typed in result to "stick" when I click away, hit enter, or select the result I just typed in. Same goes for the select options, but I am most concerned with the user inputted text.
Here's what it looks like:
The parameter createSearchChoice allows you to do just what you want. Here is an example:
<script type="text/javascript">
$("#foo").select2({
createSearchChoice:function(term, data) {
if ($(data).filter(function() {
return this.text.localeCompare(term)===0; }).length===0) {
return {id:term, text:term};
}
},
multiple: false,
data: [{id: 0, text: 'story'},{id: 1, text: 'bug'},{id: 2, text: 'task'}]
});
</script>
Taken from a closed issue at: https://github.com/ivaynberg/select2/issues/201
Fiddle: http://jsfiddle.net/pHSdP/2/
Also, make sure you add a name to the input, otherwise you won't see the value at server side
<input style="width: 200px;" type="hidden" id="foo" name="foo" />
Just a quick note for anyone else who's having a different data input. In case the console says " this.text is undefined ", make sure you check your text tag, like this:
<script type="text/javascript">
// Data input taken from "label", not "text" like usual
var lstData = [{id: 0, 'label': 'story'},{id: 1, 'label': 'bug'},{id: 2, 'label': 'task'}];
$("#foo").select2({
createSearchChoice:function(term, data) {
if ($(data).filter(function() {
return this.label.localeCompare(term)===0; }).length===0) {
return {id:term, 'label':term};
}
},
data: { results: lstData, text: 'label' }
});
</script>
Library you are using is used to filter options in a select box. It doesn't take new input, as per their own documentation:
Select2 is a jQuery based replacement for select boxes.It supports searching, remote data sets, and infinite scrolling of results.
I would suggest you to use jQueryUI Autocomplete or TypeAhead