I would like to access the filtered data of an Element UI Table.
https://element.eleme.io/#/en-US/component/table
Suppose the full data of the table looks like this:
$index: {value}
[
0: {A},
1: {B},
2: {C},
3: {D}
]
Now suppose I set a filter via filter-method on a column and the filtered dataset only leaves behind values B and D.
The table now looks like this:
[
0: {B},
1: {D}
]
whereas I would like to have the original indecies, or access the leftover data that the table shows.
[
1: {B},
3: {D}
]
How can I do this, does anyone have an idea?
I basically want to color my cells via cell-class-name but because of this behahiour, the cells are not colored correctly while the data is filtered. If I could access the remaining data OR the original indecies that would solve my problem.
Thank you!
<html>
<head>
<script src="https://unpkg.com/vue#2/dist/vue.js"></script>
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
</head>
<div id="app">
<template>
<div>
<el-table
:data="data"
style="width: 100%;"
height="600"
>
<el-table-column
label="Index"
width="60">
<template v-slot="scope">
<div class="data">
{{ scope.$index }}
</div>
</template>
</el-table-column>
<el-table-column
label="Data"
:filters="[{text: 'A', value: 'A'}, {text: 'B', value:'B'}, {text: 'C', value: 'C'}, {text: 'D', value:'D'}]"
:filter-method="filterHandler"
width="100">
<template v-slot="scope">
<div class="data">
{{ scope.row.value }}
</div>
</template>
</el-table-column>
</el-table-column>
</el-table>
</div>
</template>
</div>
<script>
new Vue({
el: '#app', //Tells Vue to render in HTML element with id "app"
data() {
return {
data: [{value: "A"},{value: "B"},{value: "C"},{value: "D"}]
}
},
methods: {
filterHandler(value, row, column) {
return row.value === value;
}
}
});
</script>
</html>
I'm new to ReactJS and I fell I'm missing some fundamental information.
I am working on simple TODO list, where you click on <li> and it gets transfered to Finished section.
http://jsbin.com/gadavifayo/1/edit?html,js,output
I have 2 arrays that contain list of tasks, when you click on one task <li> it is removed from array and transferred to other array. After that clicked <ul> is updated but not the one where task went.
When using it you may notice that <ul> is updated only when clicked.
How can I update both <ul> when clicking on only one?
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Testing</title>
<link rel="stylesheet" href="bootstrap.css">
</head>
<body>
<div id="react-app"></div>
<script src="https://fb.me/react-0.14.3.js"></script>
<script src="https://fb.me/react-dom-0.14.3.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
<script type="text/babel">
/*
* Components
*/
var pendingItems = [
'Clean the room',
'Get milf',
'Sellout and stuff'
];
var finishedItems = [
'Clean the room',
];
var TodoList = React.createClass({
getInitialState: function() {
return { items: this.props.list };
},
handleClick: function(i) {
console.log('You clicked: ' + i + ':' + this.props.listString);
if (this.props.listString == "pendingItems") {
var removed = this.state.items.splice(i, 1);
finishedItems.push(removed);
};
if (this.props.listString == "finishedItems") {
var removed = this.state.items.splice(i, 1);
pendingItems.push(removed);
};
this.forceUpdate()
},
render: function() {
return (
<ul>
{this.state.items.map(function(item, i) {
return (
<li onClick={this.handleClick.bind(this, i)} key={i}>{this.state.items[i]}</li>
);
}, this)}
</ul>
);
},
});
var Layout = React.createClass({
render: function (){
return (
<div className='col-xs-12'>
<div className='col-xs-6'>
<TodoList list={pendingItems} listString="pendingItems"/>
</div>
<div className='col-xs-6'>
<TodoList list={finishedItems} listString="finishedItems"/>
</div>
<div className='col-xs-6'></div>
</div>
)
}
});
ReactDOM.render(<Layout />, document.getElementById('react-app'));
</script>
</body>
</html>
You need to use the states. In getInitialState you put your two list, onclick do whatever transformationyou want (you then have for example updated_list1 and updated_list2 and then you set the list like that:
this.setState({ list1: updated_list1, list2: updated_list2 }); in your case this.setState({ pendingItems: pendingItems ... after the .push
the setState function will automatically rerender, no need to call forceupdate.
The second thing important here is that you have to make the two list communication kinda, so my advise would be to put your both ul in the same component (so you can manage the lists in the same component state as mentionned above).
However this is not the only way to go and you may choose the put the states of your two list in the parent component (Layout). In this case you should use this way to go. https://facebook.github.io/react/tips/expose-component-functions.html
In any case you need (if you want to keep it simple and without external model management like backbone or flux pattern) to put lists states in the same component state. (reminder: method 1 => ul in the same componenet so the states too, method 2 => keep state in the parent component)
I've a paper-dropdown-menu element. How can I show a different selected label, than valueattr is targeting at?
<link rel="import" href="components/paper-dropdown-menu/paper-dropdown-menu.html">
<link rel="import" href="components/paper-item/paper-item.html">
<polymer-element name="my-dropdown-element" attributes="selectedModus">
<template>
<paper-dropdown-menu label="Modus" on-core-select="{{modusSelect}}">
<paper-dropdown class="dropdown">
<core-menu class="menu" selected="{{selectedModus}}" valueattr="val">
<template repeat="{{d in data}}">
<paper-item val="{{d.val}}">{{d.text}}</paper-item>
</template>
</core-menu>
</paper-dropdown>
</paper-dropdown-menu>
</template>
<script>
Polymer('my-dropdown-element', {
data: [],
ready: function() {
this.data = [];
var entry = {
val: 0,
text: 'Aus'
};
this.data.push(entry);
entry = {
val: 1,
text: 'Ein'
};
this.data.push(entry);
entry = {
val: 2,
text: 'Auto'
};
this.data.push(entry);
entry = {
val: 3,
text: 'Auto (Absenken)'
};
this.data.push(entry);
}
});
</script>
</polymer-element>
When I set selectedModus = 2, the highlighted Item in the opened dropdown is auto. This is correct. But in the dropdown label there is always 0, 1, 2, 3 and not the text representation of the dropdown.
Please help me
Thanks.
edit:
I've deleted all Polymer components from my project. Then I've updated all dependencies via bower from the master's branch of each component.
Now the correct label is showing in the closed dropdown. But clicking on the arrows, doesn't open the drop down menu. I'm getting an error in the timinig-utilities.js which can be traced back to paper-dropdown-transistion.html line 152.
Very strange.
Ok i've found the answer to my problem. It seems to be a bug in the current core-animation\web-animations.html. The change mentioned here
https://github.com/zenorocha/core-animation/commit/0d047ce11e5e6b25c02f1d89b2e7aa53588d7316 worked for me.
I have a dojox/mvc/Repeat area which is bound to an array of records.
Within the row of the Repeat there is a field (the id of the record) which should be a simple display Output if the record has already been saved to the database, but it should be a TextBox if the record is new (the user must enter the value).
How do I solve this elegantly? I am fairly new to Dojo and its MVC part is very under-documented.
The most MVC-ish solution I have found so far is as follows:
1)
I put a "hasBeenSaved" property into the model which will mark the server-side saved state of the record. This attribute will be bound to the view with a transformation since the "display" style attribute of the DIV will be bound to the hasBeenSaved model attribute (one is a boolean the other is a string: "block"/"none").
2)
Within the Row, I put a conditionally visible div around the id input field. This will be visible only when the record is new, so its display style attribute is bound with an appropriate transformer attached to the Dojo MVC binding.
The same is done for the id output field but the transformer is different on the binding since this will be displayed only when the record has already been saved.
The JSFiddle which I have used to prototype this solution: http://jsfiddle.net/asoltesz/6t4dj1w7/15/
require([
"dojo/_base/declare", "dojo/dom-style", "dojo/parser", "dojo/ready",
"dijit/_WidgetBase", "dijit/_TemplatedMixin",
'dojox/mvc/getStateful'
], function(
declare, domStyle, parser, ready,
_WidgetBase, _TemplatedMixin,
getStateful
){
// setting up the data model for MVC
model = {
items: [
{ id: 'id1',
hasBeenSaved: true
},
{ id: null,
hasBeenSaved: false
},
{ id: null,
hasBeenSaved: false
},
{ id: 'id3',
hasBeenSaved: true
}
]
};
model = getStateful(model);
/**
* This mixin makes it possible to set the "display" style property of
* the DOM node (of any widget) as a Widget property and thus bind it to an MVC model
* when needed.
*/
declare("_DisplayAttributeMixin", [], {
// parameters
display: "block",
_setDisplayAttr: function(/*String*/ display){
this._set("display", display);
domStyle.set(this.domNode, "display", display);
}
});
/** Transformer methods for converting hasBeenSaved to visible/hidden values */
transfSavedToHidden = {format: function(hasBeenSaved){
console.log("transfSavedToHidden: " + (hasBeenSaved ? "none" : "block"));
return hasBeenSaved ? "none" : "block";
}};
transfSavedToVisible = {format: function(hasBeenSaved){
console.log("transfSavedToHidden: " + (hasBeenSaved ? "block" : "none"));
return hasBeenSaved ? "block" : "none";
}};
ready(function(){
// Call the parser manually so it runs after our mixin is defined, and page has finished loading
parser.parse();
});
});
The HTML markup:
<script type="dojo/require">at: "dojox/mvc/at"</script>
<div
data-dojo-type="dojox/mvc/Group"
data-dojo-props="target: model"
>
<div id="repeatId"
data-dojo-type="dojox/mvc/Repeat"
data-dojo-props="children: at('rel:', 'items')"
>
<div
data-dojo-type="dojox/mvc/Group"
data-dojo-props="target: at('rel:', ${this.index})"
>
<span>Record: ${this.index}</span>
<!-- This is displayed only when the record is new (not saved yet) -->
<div
data-dojo-type="dijit/_WidgetBase"
data-dojo-mixins="_DisplayAttributeMixin"
data-mvc-bindings="
display: at('rel:', 'hasBeenSaved')
.direction(at.from)
.transform(transfSavedToHidden)"
>
<label for="idInput${this.index}">id:</label>
<input
data-dojo-type="dijit/form/TextBox"
id="idInput${this.index}"
data-dojo-props="value: at('rel:', 'id')"
></input>
</div> <!-- end conditionally hidden div -->
<!-- This is displayed only when the record has already been saved -->
<div
data-dojo-type="dijit/_WidgetBase"
data-dojo-mixins="_DisplayAttributeMixin"
data-mvc-bindings="
display: at('rel:', 'hasBeenSaved')
.direction(at.from)
.transform(transfSavedToVisible)"
>
<label for="idInput${this.index}">id:</label>
<span
data-dojo-type="dojox/mvc/Output"
id="idOutput${this.index}"
data-dojo-props="value: at('rel:', 'id')"
></span>
</div> <!-- end conditionally hidden div -->
<hr/>
</div> <!-- end of row -->
</div> <!-- end of Repeat -->
</div> <!-- end of Group -->
A secondary, less complex solution:
Bind the "hasBeenSaved" property to a hidden text within the repeating div.
Put an onChange event on the hidden field which gets the index of the repeat as well.
The onChange event simply hides the field which is not appropriate in light of the hasBeenChanged property value for the record.
The fiddle is here: http://jsfiddle.net/asoltesz/8u9js6sz/5/
Code:
hasBeenSavedChanged = function(field, index) {
var divToHide
if (field.value == true) {
divToHide = "idInputDiv"
}
else {
divToHide = "idOutputDiv"
}
var div = document.getElementById(divToHide + index);
div.style.display = "none";
}
require([
"dojo/_base/declare", "dojo/dom-style", "dojo/parser", "dojo/ready",
"dijit/_WidgetBase", "dijit/_TemplatedMixin",
'dojox/mvc/getStateful'
], function(
declare, domStyle, parser, ready,
_WidgetBase, _TemplatedMixin,
getStateful
){
// setting up the data model for MVC
model = {
items: [
{ id: 'id1',
hasBeenSaved: true
},
{ id: null,
hasBeenSaved: false
},
{ id: null,
hasBeenSaved: false
},
{ id: 'id3',
hasBeenSaved: true
}
]
};
model = getStateful(model);
ready(function(){
// Call the parser manually so it runs after our mixin is defined, and page has finished loading
parser.parse();
});
});
HTML:
<script type="dojo/require">at: "dojox/mvc/at"</script>
<div
data-dojo-type="dojox/mvc/Group"
data-dojo-props="target: model"
>
<span id="itemsCtl"
data-dojo-type="dojox/mvc/ListController"
data-dojo-props="model: model.items">
</span>
<div id="itemsRepeat"
data-dojo-type="dojox/mvc/Repeat"
data-dojo-props="children: at('rel:', 'items')"
>
<div
data-dojo-type="dojox/mvc/Group"
data-dojo-props="target: at('rel:', ${this.index})"
>
<span>Record: ${this.index}</span>
<input
id="hasBeenChanged${this.index}"
data-dojo-type="dijit/form/TextBox"
data-dojo-props="value: at('rel:', 'hasBeenSaved')"
onChange="hasBeenSavedChanged(this, '${this.index}');"
type="hidden"
></input>
<!-- This is displayed only when the record is new (not saved yet) -->
<div id="idInputDiv${this.index}"
>
<label for="idInput${this.index}">id:</label>
<input
data-dojo-type="dijit/form/TextBox"
id="idInput${this.index}"
data-dojo-props="value: at('rel:', 'id')"
></input>
</div> <!-- end conditionally hidden div -->
<!-- This is displayed only when the record has already been saved -->
<div id="idOutputDiv${this.index}" >
<label for="idInput${this.index}">id:</label>
<span
data-dojo-type="dojox/mvc/Output"
id="idOutput${this.index}"
data-dojo-props="value: at('rel:', 'id')"
></span>
</div> <!-- end conditionally hidden div -->
<hr/>
</div> <!-- end of row -->
</div> <!-- end of Repeat -->
</div> <!-- end of Group -->
Mixin/transformer approach is something I had in mind, too. Two things I’d add there are out-of-the-box Dijit features, one is dijitDisplayNone class, another is attribute mapping feature.
Though it’s strange that the former is undocumented, the intent may have been for private usage within Dijit codebase.
Though it’s a bit hackish (and may be broken in future 1.x Dijit releases), overriding the Dijit code that’s responsible for attribute mapping will allow you to map a widget attribute to a CSS class that’s toggled.
Here’s a code sample that uses the above two:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="//ajax.googleapis.com/ajax/libs/dojo/1.10.1/dojo/resources/dojo.css">
<link rel="stylesheet" type="text/css" href="//ajax.googleapis.com/ajax/libs/dojo/1.10.1/dijit/themes/dijit.css">
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/dojo/1.10.1/dojo/dojo.js" data-dojo-config="async: 1, parseOnLoad: 0"></script>
<script type="text/javascript">
require([
"dojo/_base/array",
"dojo/_base/declare",
"dojo/_base/lang",
"dojo/dom-class",
"dojo/parser",
"dojox/mvc/getStateful",
"dijit/form/TextBox"
], function(array, declare, lang, domClass, parser, getStateful){
declare("CssToggleMixin", null, {
// summary:
// Mixin class to support widget attributes with toggleClass type.
// toggleClass type allows boolean value of an attribute to reflect existence of a CSS class in a DOM node in the widget.
_attrToDom: function(/*String*/ attr, /*String*/ value, /*Object?*/ commands){
// summary:
// Handle widget attribute with toggleClass type.
// See dijit/_WidgetBase._attrToDom() for more details.
var callee = arguments.callee;
array.forEach((function(){ return lang.isArray(commands) ? commands.slice(0) : [commands]; })(arguments.length >= 3 ? commands : this.attributeMap[attr]), function(command){
command.type != "toggleClass" ?
this.inherited("_attrToDom", lang.mixin([attr, value, command], {callee: callee})) :
domClass.toggle(this[command.node || "domNode"], command.className || attr, value);
}, this);
}
});
flipConverter = {
format: function (value) {
return !value;
},
parse: function (value) {
return !value;
}
};
model = getStateful({
items: [
{
value: "Foo",
hasBeenSaved: true
},
{
hasBeenSaved: false
},
{
hasBeenSaved: false
},
{
value: "Bar",
hasBeenSaved: true
}
]
});
parser.parse();
})
</script>
</head>
<body>
<script type="dojo/require">at: "dojox/mvc/at"</script>
<div data-dojo-type="dojox/mvc/WidgetList"
data-dojo-mixins="dojox/mvc/_InlineTemplateMixin"
data-dojo-props="children: at(model, 'items')">
<script type="dojox/mvc/InlineTemplate">
<div>
<span data-dojo-type="dijit/_WidgetBase"
data-dojo-mixins="CssToggleMixin"
data-dojo-props="value: at('rel:', 'value'),
noDisplay: at('rel:', 'hasBeenSaved').transform(flipConverter),
_setValueAttr: {node: 'domNode', type: 'innerText'},
_setNoDisplayAttr: {type: 'toggleClass', className: 'dijitDisplayNone'}"></span>
<span data-dojo-type="dijit/form/TextBox"
data-dojo-mixins="CssToggleMixin"
data-dojo-props="value: at('rel:', 'value'),
noDisplay: at('rel:', 'hasBeenSaved'),
_setNoDisplayAttr: {type: 'toggleClass', className: 'dijitDisplayNone'}"></span>
</div>
</script>
</div>
</body>
</html>
Hope it’ll shed some light.
Best, Akira
I have a KendoUI grid that is defined in my code using the Knockout-Kendo plugin as follow. It is important to note that this grids number of columns changes depending on the json received from the server.
<script type="text/html" id="grid">
<div class="grid-input input" data-bind="kendoGrid:
{
data: RowList,
columns: ko.toJS(GridHeader.ColumnDefinitionList),
rowTemplate: 'kendoui-grid-row',
altRowTemplate: 'kendoui-alt-grid-row',
useKOTemplates: true,
scrollable: false,
pageable: { pageSize: 10 },
sortable: true
}"></div>
</script>
<script type="text/html" id="kendoui-grid-row">
<tr data-bind="visible: IsDeleted() == false, template: { name: 'grid-row' }"></tr>
</script>
<script type="text/html" id="kendoui-alt-grid-row">
<tr data-bind="visible: IsDeleted() == false, template: { name: 'grid-row' }" class="k-alt"></tr>
</script>
<script type="text/html" id="grid-row">
<td><div class="grid-button delete-row-button"><span class="icon-delete"></span></div></td>
<!-- ko foreach: CellList -->
<td data-bind="template: { name: Input.Type, data: Input }">
</td>
<!-- /ko -->
</script>
<script type="text/html" id="text">
<input class="text-input input k-textbox" data-bind="value: Value" />
</script>
In this case, I have a grid filled with text boxes (in each cells of the grid, there is an input of type text). Now my problem is that sorting by clicking the grid headers does nothing even if there is texts in the inputs. What I would like to do is be able to define the target of the sorting. In this case it would be the value of the input inside the grid cells.
I've ran into a similar problem a while ago. The problem was that the Kendo Grid doesn't work well with ko observables. As a workaround you can create a computed which returns the data as a plain JS object:
this.RowList.asJS = ko.computed(function() {
return ko.toJS(this.RowList());
}, this);
Then change data: RowList with the following:
data: RowList.asJS
This however means you lose the observables in your row templates. A workaround for this is to get the original object again inside your row.
First create a helper function to quickly get an item by ID (assuming you have an Id property):
this.RowList.getById = function(id) {
return ko.utils.arrayFirst(this.RowList(), function(row) {
return ko.unwrap(row.Id) === id;
});
}, this);
Now you can call getById inside your row templates:
<script type="text/html" id="kendoui-grid-row">
<!-- ko with: $root.RowList.getById(Id) -->
<tr data-bind="visible: IsDeleted() == false, template: { name: 'grid-row' }"></tr>
<!-- /ko -->
</script>