Domain
class Example {
String title
Date releaseDate
String author
Boolean paperback
static constraints = {
}
}
Controller
class ExampleController {
def scaffold = true
def search = {
exampleInstance = Example.findAllByTitleIlike("${params.q}%",[max:10, offset:0, sort:"title", order:"asc"])
redirect(action: "list",params)
return
}
def list = {
params.max = Math.min(params.max ? params.int('max') : 10, 100)
[exampleInstanceList: Example.list(params),
exampleInstanceTotal: Example.count()]
}
}
View
<div id="search">
<g:form url='[controller: "example", action: "search"]' id="search" name="search" method="get">
<g:textField name="q" value="${params.q}" />
<input type="submit" value="Find" />
</g:form>
</div>
Please Help me is how
Error URI /test3/example/search Class groovy.lang.MissingPropertyException
Message No such property: exampleInstance for class: test3.ExampleController
Use render instead of redirect and pass all the model that are required for the list page.
def search = {
def exampleInstance= Example.findAllByTitleIlike("${params.q}%",[max:10, offset:0, sort:"title", order:"asc"])
render( view:list, model:[ exampleInstance:exampleInstance, params:params ] )
Related
I have two classes:
Row (Child Class)
mySpreadsheet (Parent Class)
I am trying to do something like this:
Row:
class Row extends React.Component {
constructor(props, ref) {
super(props);
this.state = { selectedFile: null}
this.handleUpload = this.handleUpload.bind(this);
}
//This handleUpload is being called by the parent class of this Row class through ref.
handleUpload(ev) {
ev.preventDefault();
const data = new FormData();
data.append('file', this.uploadInput.files[0]);
data.append('filename', this.fileName.value);
data.append('comment',this.comment.value);
data.append('id', this.fileName.id);
fetch('http://localhost:8000/upload', {
method: 'POST',
body: data,
}).then((response) => {
response.json().then((body) => {
this.setState({ selectedFile: `http://localhost:8000/${body.file}` });
});
});
}
rowCreator() {
let row = []
for (var i = 0; i < 10; i++) {
row.push(
<td>
<div>
<input type="file" name={`file${this.props.id*10 + i}`} id={this.props.id*10 + 1} ref={(ref) => { this.uploadInput = ref; }}/>
<input type="text" name={`fileName ${this.props.id*10 + i}`} ref={(ref) => { this.fileName = ref; }} placeholder="Name the file with extension"/>
<input type="text" ref={(ref) => { this.comment = ref; }} placeholder="Comment"/>
</div>
</td>
)
}
return row
}
render() {
return (
<tr>
<td class="align-middle ">
<div class="cell">
<input type="text" placeholder={this.props.id + 1} />
</div>
</td>
{this.rowCreator()}
</tr>
)
}
}
and in mySpreadsheet I am creating each row in a table using Row class as follows:
<tbody id="tbody">
{this.state.data.map(id => (
<Row id={id} ref={this.rowRef} />
))}
</tbody>
I am using the handleUpload() function from the Row (child) by using rowRef:
this.rowRef = React.createRef();
upload(ev) {
this.rowRef.current.handleUpload(ev);
}
<button onClick={this.upload}>
Upload Files
</button>
But I am getting error (500) while doing a POST request through my website. Is it because of the ref I am using in Row such as uploadInput, for appending data in handleUpload? Is there any way to make a unique ref for all the cells in my table? Or can I use something else like id or name which I have made uniquely for all different cells using this.props.id*10 + i for each iteration, i while making columns for one row?
You can create refs for mapped elements and put it in an array based on their indexes or ids.
// constructor state part
constructor() {
this.refs = [];
}
// render part
{this.state.data.map(id => (
return <Row id={id} ref={itemRef => this.refs[id] = itemRef} />
))}
And in my opinion, you should hold the values instead of the components itself in an array.
Id must be unique and if the map parameter is an object, you should use a unique property instead of the key which comes with map. If you use keys, React will not keep track of your component while you' re updating your state.
I have a form in React, with an Input and Search Button. Currently the Search Button is doing performing the search. I want if a user presses the Enter in Field, Search Button is triggered.
Currently Enter just clears the Input Field. I have onClickhandler on Search Button. I want to apply same handler on Keydown or Keypress event on Field as well.
Below is my code:
import React, {Component} from 'react';
import {FormattedMessage} from 'react-intl';
import {FormField, Form} from 'digitalexp-common-components-l9';
import Input from 'digitalexp-common-components-l9/lib/form-field/Input';
import messages from 'digitalexp-select-additional-charges-retail-module-l9/src/widget/SelectAdditionalCharges.i18n';
const {FormContainer} = Form;
#FormContainer({hasDefaults: true})
export default class SelectAdditionalChargesSearchBoxView extends Component {
constructor(props) {
super(props);
this.handleSearchClick = this.handleSearchClick.bind(this);
this.handleClearClick = this.handleClearClick.bind(this);
}
componentWillMount() {
this.props.initializeFormValues({searchkey: this.props.searchBy});
}
handleClearClick() {
const {updateField} = this.props;
updateField({name: 'searchkey', value: ''}).then(() => this.props.handleSearchBy({searchkey: ''}));
}
handleSearchClick(e) {
const {handleSubmit, handleSearchBy} = this.props;
e.preventDefault();
handleSubmit(handleSearchBy);
}
render() {
const {Field} = FormField;
return (
<div className="ds-search-panel">
<div className="ds-search-panel__header">
<FormattedMessage {...messages.SelectSearchAdditionalCharges} />
</div>
<form
className="ds-search-panel__footer"
autoComplete="off"
onSubmit={this.handleSearchClick}>
<span className="ds-search-panel__footer--names">
<FormattedMessage {...messages.nameLabel} />
</span>
<span className="ds-search-panel__footer--textfields">
<Field
Component={Input}
name="searchkey"
autoComplete="off"
config={{rowLabel: true}}
/>
</span>
<span className="ds-search-panel__footer--search">
<button className="ds-btn ds-btn--secondary ds-btn--searches" onClick={this.handleClearClick}>
<span className="ds-btn--span">
<FormattedMessage {...messages.clearButtonText} />
</span>
</button>
<button className="ds-btn ds-btn--primary ds-btn--searches" onClick={this.handleSearchClick}>
<span className="ds-btn--span">
<FormattedMessage {...messages.searchButtonText} />
</span>
</button>
</span>
</form>
</div>
);
}
}
And below is the Input.js class:
import React from 'react';
import classNames from 'classnames';
const Input = (props) => {
const {
input, label, type = 'text', usePlaceholder, meta: {error}, displayInlineError = true,
fieldIconClassName, showCloseButton, fieldIconEventListener, clearField
} = props;
let {fieldClassName = 'ds-text'} = props;
const {name, placeholder} = input;
fieldClassName = classNames('ds-form__input', {
[fieldClassName]: fieldClassName
});
let fieldIconProps = {
className: classNames({
'ds-form__icon': true,
[fieldIconClassName]: fieldIconClassName
})
};
if (fieldIconEventListener) {
fieldIconProps = {
...fieldIconProps,
onClick: fieldIconEventListener
};
}
return (
<div className="ds-form__input--wrapper">
<input
id={name}
{...input}
placeholder={usePlaceholder ? placeholder || label : ''}
type={type}
className={fieldClassName}
/>
{showCloseButton && <button className="ds-form__icon ds-form__icon--close" onMouseDown={clearField} />}
{fieldIconClassName && <div {...fieldIconProps} />}
{(error && displayInlineError) && <div className="ds-notification__error--text">{error}</div>}
</div>
);
};
export default Input;
Could anyone help?
You can just attach onKeyDown or onKeyUp handler to Field
handleKeyPress (e) {
// This is perfectly safe in react, it correctly detect the keys
if(event.key == 'Enter'){
this.handleSearchClick(e)
}
}
<Field onKeyDown={this.handleKeyPress}
I've been struggling to make this react virtualized table example work & seriously starting to doubt my sanity. I've created a react app and I'm just trying to render the example table inside App.js with this:
class App extends Component {
render() {
var data = [1,2,3,4,5,6,7,8,9,10];
return (
<TableExample
list={data}
/>
);
}
}
React keeps saying list isn't defined - it seems obvious I'm not getting the data into the component the right way. I haven't been able to understand the example code, what props need to be passed in and what they should be named. Sorry for the stupid question but I've been stuck forever not knowing where else to find an answer. The table example code is below:
/** #flow */
import Immutable from 'immutable';
import PropTypes from 'prop-types';
import * as React from 'react';
import {
ContentBox,
ContentBoxHeader,
ContentBoxParagraph,
} from '../demo/ContentBox';
import {LabeledInput, InputRow} from '../demo/LabeledInput';
import AutoSizer from '../AutoSizer';
import Column from './Column';
import Table from './Table';
import SortDirection from './SortDirection';
import SortIndicator from './SortIndicator';
import styles from './Table.example.css';
export default class TableExample extends React.PureComponent {
static contextTypes = {
list: PropTypes.instanceOf(Immutable.List).isRequired,
};
constructor(props, context) {
super(props, context);
const sortBy = 'index';
const sortDirection = SortDirection.ASC;
const sortedList = this._sortList({sortBy, sortDirection});
this.state = {
disableHeader: false,
headerHeight: 30,
height: 270,
hideIndexRow: false,
overscanRowCount: 10,
rowHeight: 40,
rowCount: 1000,
scrollToIndex: undefined,
sortBy,
sortDirection,
sortedList,
useDynamicRowHeight: false,
};
this._getRowHeight = this._getRowHeight.bind(this);
this._headerRenderer = this._headerRenderer.bind(this);
this._noRowsRenderer = this._noRowsRenderer.bind(this);
this._onRowCountChange = this._onRowCountChange.bind(this);
this._onScrollToRowChange = this._onScrollToRowChange.bind(this);
this._rowClassName = this._rowClassName.bind(this);
this._sort = this._sort.bind(this);
}
render() {
const {
disableHeader,
headerHeight,
height,
hideIndexRow,
overscanRowCount,
rowHeight,
rowCount,
scrollToIndex,
sortBy,
sortDirection,
sortedList,
useDynamicRowHeight,
} = this.state;
const rowGetter = ({index}) => this._getDatum(sortedList, index);
return (
<ContentBox>
<ContentBoxHeader
text="Table"
sourceLink="https://github.com/bvaughn/react-virtualized/blob/master/source/Table/Table.example.js"
docsLink="https://github.com/bvaughn/react-virtualized/blob/master/docs/Table.md"
/>
<ContentBoxParagraph>
The table layout below is created with flexboxes. This allows it to
have a fixed header and scrollable body content. It also makes use of{' '}
<code>Grid</code> for windowing table content so that large lists are
rendered efficiently. Adjust its configurable properties below to see
how it reacts.
</ContentBoxParagraph>
<ContentBoxParagraph>
<label className={styles.checkboxLabel}>
<input
aria-label="Use dynamic row heights?"
checked={useDynamicRowHeight}
className={styles.checkbox}
type="checkbox"
onChange={event =>
this._updateUseDynamicRowHeight(event.target.checked)
}
/>
Use dynamic row heights?
</label>
<label className={styles.checkboxLabel}>
<input
aria-label="Hide index?"
checked={hideIndexRow}
className={styles.checkbox}
type="checkbox"
onChange={event =>
this.setState({hideIndexRow: event.target.checked})
}
/>
Hide index?
</label>
<label className={styles.checkboxLabel}>
<input
aria-label="Hide header?"
checked={disableHeader}
className={styles.checkbox}
type="checkbox"
onChange={event =>
this.setState({disableHeader: event.target.checked})
}
/>
Hide header?
</label>
</ContentBoxParagraph>
<InputRow>
<LabeledInput
label="Num rows"
name="rowCount"
onChange={this._onRowCountChange}
value={rowCount}
/>
<LabeledInput
label="Scroll to"
name="onScrollToRow"
placeholder="Index..."
onChange={this._onScrollToRowChange}
value={scrollToIndex || ''}
/>
<LabeledInput
label="List height"
name="height"
onChange={event =>
this.setState({height: parseInt(event.target.value, 10) || 1})
}
value={height}
/>
<LabeledInput
disabled={useDynamicRowHeight}
label="Row height"
name="rowHeight"
onChange={event =>
this.setState({
rowHeight: parseInt(event.target.value, 10) || 1,
})
}
value={rowHeight}
/>
<LabeledInput
label="Header height"
name="headerHeight"
onChange={event =>
this.setState({
headerHeight: parseInt(event.target.value, 10) || 1,
})
}
value={headerHeight}
/>
<LabeledInput
label="Overscan"
name="overscanRowCount"
onChange={event =>
this.setState({
overscanRowCount: parseInt(event.target.value, 10) || 0,
})
}
value={overscanRowCount}
/>
</InputRow>
<div>
<AutoSizer disableHeight>
{({width}) => (
<Table
ref="Table"
disableHeader={disableHeader}
headerClassName={styles.headerColumn}
headerHeight={headerHeight}
height={height}
noRowsRenderer={this._noRowsRenderer}
overscanRowCount={overscanRowCount}
rowClassName={this._rowClassName}
rowHeight={useDynamicRowHeight ? this._getRowHeight : rowHeight}
rowGetter={rowGetter}
rowCount={rowCount}
scrollToIndex={scrollToIndex}
sort={this._sort}
sortBy={sortBy}
sortDirection={sortDirection}
width={width}>
{!hideIndexRow && (
<Column
label="Index"
cellDataGetter={({rowData}) => rowData.index}
dataKey="index"
disableSort={!this._isSortEnabled()}
width={60}
/>
)}
<Column
dataKey="name"
disableSort={!this._isSortEnabled()}
headerRenderer={this._headerRenderer}
width={90}
/>
<Column
width={210}
disableSort
label="The description label is really long so that it will be truncated"
dataKey="random"
className={styles.exampleColumn}
cellRenderer={({cellData}) => cellData}
flexGrow={1}
/>
</Table>
)}
</AutoSizer>
</div>
</ContentBox>
);
}
_getDatum(list, index) {
return list.get(index % list.size);
}
_getRowHeight({index}) {
const {list} = this.context;
return this._getDatum(list, index).size;
}
_headerRenderer({dataKey, sortBy, sortDirection}) {
return (
<div>
Full Name
{sortBy === dataKey && <SortIndicator sortDirection={sortDirection} />}
</div>
);
}
_isSortEnabled() {
const {list} = this.context;
const {rowCount} = this.state;
return rowCount <= list.size;
}
_noRowsRenderer() {
return <div className={styles.noRows}>No rows</div>;
}
_onRowCountChange(event) {
const rowCount = parseInt(event.target.value, 10) || 0;
this.setState({rowCount});
}
_onScrollToRowChange(event) {
const {rowCount} = this.state;
let scrollToIndex = Math.min(
rowCount - 1,
parseInt(event.target.value, 10),
);
if (isNaN(scrollToIndex)) {
scrollToIndex = undefined;
}
this.setState({scrollToIndex});
}
_rowClassName({index}) {
if (index < 0) {
return styles.headerRow;
} else {
return index % 2 === 0 ? styles.evenRow : styles.oddRow;
}
}
_sort({sortBy, sortDirection}) {
const sortedList = this._sortList({sortBy, sortDirection});
this.setState({sortBy, sortDirection, sortedList});
}
_sortList({sortBy, sortDirection}) {
const {list} = this.context;
return list
.sortBy(item => item[sortBy])
.update(
list => (sortDirection === SortDirection.DESC ? list.reverse() : list),
);
}
_updateUseDynamicRowHeight(value) {
this.setState({
useDynamicRowHeight: value,
});
}
}
Looking at some previous questions, it seems that the example is using some components that are not included inside dist package. Thats probably why you are getting undefined error.
Here is the most basic example of Tables in react virtulized:
import React from 'react';
import ReactDOM from 'react-dom';
import { Column, Table } from 'react-virtualized';
import 'react-virtualized/styles.css'; // only needs to be imported once
// Table data as an array of objects
const list = [
{ name: 'Brian Vaughn', description: 'Software engineer' }
// And so on...
];
// Render your table
ReactDOM.render(
<Table
width={300}
height={300}
headerHeight={20}
rowHeight={30}
rowCount={list.length}
rowGetter={({ index }) => list[index]}
>
<Column
label='Name'
dataKey='name'
width={100}
/>
<Column
width={200}
label='Description'
dataKey='description'
/>
</Table>,
document.getElementById('example')
);
When learning new library, its always best to start with the most simple example then expand on it. Here is the link to the full table docs.
The issue with the example is that in order for contextTypes to work, the parent component needs to define corresponding contextTypes and a getChildContext function.
In the parent component:
class App extends React.Component {
static childContextTypes = {
list: PropTypes.instanceOf(Immutable.List).isRequired
};
getChildContext() {
return {
list
};
}
render() {
return <TableExample />;
}
}
Mentioned in this issue; see lines 48-53 and 68-76 of the react-virtualized demo Application.js.
I encountered problem with react component. Basically, i use NPM integrated with Rails and called React component in my rails app.
I try to call react-file-base64 module in my code like below :
const FileBase64 = require('react-file-base64');
var MembersNew = React.createClass(
{
render()
{
return(
<div>
<h5>ACCOUNT DETAILS</h5>
<hr/>
<p>Fill in your member account details below</p>
<b>Membership ID : </b>
<div className="row">
<div className="medium-6 columns">
<FileBase64/> <------ Called component
<label>Username*
<input ref="name" type="text"/>
</label>
<label>First Name*
<input ref="name" type="text"/>
</label>
<label>Last Name*
<input ref="name" type="text"/>
</label>
<label>Email Address*
<input ref="name" type="text"/>
</label>
</div>
</div>
)
I got following error :
Below is react-file-base64.js :
import React from 'react';
import ReactDOM from 'react-dom';
class FileBase64 extends React.Component {
constructor() {
super()
this.state = {
files: []
}
this.props = {
multiple: false
}
}
handleChange(e){
// get the files
let files = e.target.files;
// Process each file
var allFiles = []
for (var i = 0; i < files.length; i++) {
let file = files[i]
// Make new FileReader
let reader = new FileReader()
// Convert the file to base64 text
reader.readAsDataURL(file)
// on reader load somthing...
reader.onload = () => {
// Make a fileInfo Object
let fileInfo = {
name: file.name,
type: file.type,
size: Math.round(file.size / 1000)+' kB',
base64: reader.result,
file: file
}
// Push it to the state
allFiles.push(fileInfo)
// If all files have been proceed
if(allFiles.length == files.length){
// Apply Callback function
if(this.props.multiple) this.props.onDone(allFiles)
else this.props.onDone(allFiles[0])
}
} // reader.onload
} // for
}
render(){
return (
<div>
<input
type="file"
onChange={ this.handleChange.bind(this) }
multiple={ this.props.multiple } />
</div>
)
}
}
export default FileBase64;
I think what i did was wrong. If there's anyone could guide me on how can i achieve this. I really appreciate that.
I'm using MVC5 and I want to search for a result and stay at the same page, here is my method in my controller (LiaisonsProjetsPPController) that do the operation of searching :
public ActionResult IndexAjoutML(int id, string SearchString)
{
PartiesPrenantesEntities db = new PartiesPrenantesEntities();
ViewBag.idProjet = id;
ViewBag.searchString = SearchString;
IQueryable<ActivitesPP> qry = this.db.ActivitesPP.Intersect(from item in this.db.LiaisonsProjetsPP where item.idProjet == id select item.ActivitesPP).Include(model => model.Activites.CatActivites);
var act = from s in db.CatActivites
select s;
if (!String.IsNullOrEmpty(SearchString))
return PartialView("~/Views/ActivitesPP/IndexAjoutProjet.cshtml", this.db.ActivitesPP.Where(s => s.PartiesPrenantes.nomPP.Contains(SearchString)).Except(qry));
else
return PartialView("~/Views/ActivitesPP/IndexAjoutProjet.cshtml", this.db.ActivitesPP.Except(qry));
}
Then in my view (Views/ActivitesPP/IndexAjoutProjet) I have my search form and the div of the display result :
#using (Ajax.BeginForm("IndexAjoutML", "LiaisonsProjetsPP", FormMethod.Post,
new AjaxOptions
{
InsertionMode = InsertionMode.Replace,
HttpMethod = "POST",
UpdateTargetId = "search-results"
}, new { #id = "searchFormPP" }))
{
<p>
<label>Partie prenante: </label> #Html.TextBox("SearchString")
<input id="inputRecherche" name="SearchString" type="submit" value="Rechercher" />
</p>
}
<div id="search-results">
#{foreach (var catactivite in Model.GroupBy(model => model.Activites.CatActivites))
{
String couleurCategorie = catactivite.Key.couleurCategorie;
String couleurTexte = CustomHelpers.GetForegroundColor(couleurCategorie);
//Image de la partie prenante
<div class="panel-heading unhide" style="background-image: none; color: #couleurTexte; background-color: #couleurCategorie; padding: 2px;">
</div>
foreach (var pp in catactivite)
{
String nomPP = (pp.idPP == null ? "Inconnu" : pp.PartiesPrenantes.nomPP);
String dateAffichee;
String imgPP = "../../Images/Profils/" + (pp.PartiesPrenantes.imgPP ?? "avatar.png");
if (pp.finActivite == null)
{
dateAffichee = "Depuis le " + String.Format("{0:d/MM/yyyy}", pp.debutActivite);
}
else
{
dateAffichee = "Depuis le " + String.Format("{0:d/MM/yyyy}", pp.debutActivite) + ", jusqu'au " + String.Format("{0:d/MM/yyyy}", pp.finActivite);
}
<div class="panel panel-primary">
<div class="panel-heading unhide" style="color: #couleurTexte; background-color: #couleurCategorie;">
<div style="float: left">
<img class="imgPP img-circle" src="#(imgPP)" />
</div>
<h5>#pp.Activites.libelleActivite (#Html.Raw(pp.idLieu == 999 ? "National" : pp.Lieux.nomLieu))</h5>
<h6>#pp.PartiesPrenantes.nomPP</h6>
</div>
<div class="panel-body hiddenPart">
#if (pp.idPP != null)
{
<label>Commentaire</label>
<p>#(pp.commentaireActivite ?? "Pas plus de détails..")</p>
#Html.Action("CreateForm", "LiaisonsProjetsPP", new { idActivite = pp.idActivite, idProjet = ViewBag.idProjet })
}
</div>
</div>
}
}
}
</div>
}
else
{
#Html.Raw("<p>Aucune partie prenante disponible..")
#Html.Raw("(attention: pour être ajoutée, une partie prenante doit posséder au moins une activité référencée..)</p>")
}
In my view i call my method of search (Views/Projets/Details): #{ Html.RenderAction("IndexAjoutML", "LiaisonsProjetsPP", new { idProjet = Model.idProjet, searchString = Model.searchString }); }
The search work but it redirects me to another page http://localhost:49612/LiaisonsProjetsPP/IndexAjout/1 instead of staying at this page http://localhost:49612/Projets/Details/1.
What you are trying to do seems to be loading results unobtrusively with an AJAX form. The Professional ASP.NET MVC 5 book by John Galloway et al. has a nice section on this, but realizing that no one reads books I will provide a link to a site with a code sample for it.
The .NET Funda site describes here exactly how to search and return the results to the same page without a complete refresh using unobtrusive-ajax.
Likely what you are missing is a reference to jquery.unobtrusive-ajax.min.js. Other posts on Stack Overflow also reference this topic, but I realize you might not know the correct search terms. Try looking further into "AJAX partial view unobtrusive loading" as search terms for further research.
This example is from the book I mentioned from John Galloway.
A JavaScript error message.
function searchFailed(){
$("#searchresults").html("Sorry, there was a problem searching.");
}
This is what a simple Ajax form should look like. Note the "GET" form method.
<div class="panel panel-default">
<div class="panel-heading">
Artist Search
</div>
<div class="panel-body">
#using(Ajax.BeginForm("ArtistSearch", "Home",
new AjaxOptions
{
InsertionMode = InsertionMode.Replace,
HttpMethod = "GET",
OnFailure = "searchFailed",
LoadingElementID = "ajax-loader",
UpdateTargetId = "searchresults",
}))
{
<input type="text" name="q" />
<input type="submit" value="search" />
<img id="ajax-loader"
src="#Url.Content("~/Images/ajax-loader.gif")"
style="display:none" />
}
<div id="searchresults"></div>
</div>
</div>
This is the method responsible for returning the partial view:
public ActionResult ArtistSearch(string q)
{
var artists = GetArtists(q);
return PartialView(artists);
}
This is a search method.
public List<Artist> GetArtists(string searchString)
{
return storeDB.Artist.Where(a => a.Name.Contains(searchString)).ToList();
}
Note that the method for returning the partial view is simply "return PartialView(model);"