Assuming we have :
class Email extends React.Component{
constructor(props){
super(props);
}
validate(){
return true;
}
render(){
<input placeholder={this.is.what.i.ask.for.to.be.parsed.from.its.body} onFocus={this.validate} />
}
}
Now When , I resue it, i want to call :
<Email >
someone#company.com
</Email>
How to parse someone#company.com from the body of Email tag.
I Knew that it can be done by calling <Email holder="someone#company.com" /> & i must update render by this.props.holder.
Therefore, we access to React Attributes by this.props, HOWEVER, Is there something to access its body with the Built-in way ?
If I understand you correctly, then you should use this.props.children:
render() {
return (<input placeholder={this.props.children} onFocus={this.validate} />);
}
As an aside, remember that you need to bind this for your onFocus callback! A popular way to do this is from within the constructor:
constructor(props) {
super(props);
this.validate = this.validate.bind(this);
}
this.props.children gives you access to a Component's children. In this case the email address content would be considered a child of Email Component.
It would probably be best to use the React.Children.only utility to make sure that there is only a single child.
Something like this should work:
class Email extends React.Component{
constructor(props){
super(props);
}
validate(){
return true;
}
render(){
return <input placeholder={React.Children.only(this.props.children)} onFocus={this.validate} />;
}
}
Related
my antd table is not updating when selectedId property changes:
rowClassName={row => row.id === this.model.selectedId
? row.nameWithTypeAndRunType.type + " " + SELECTED_ROW_CSS_CLASS
: row.nameWithTypeAndRunType.type
}
i have an workaround, where i extract the table to a constant:
const MyTable = (viewModel: MyModel) => (
<Table<MyModel>
........
and add in render() with <MyTable {...this.myModel} />
I'd like to create a RTable, so that i could generally use the antd Table conveniently. I tried this:
export function RTable<RecordType extends object = any>(props: TableProps<RecordType>): JSX.Element {
const t = <Observer>{() => <Table {...props} />}</Observer>
return t
}
Than i use in render() RTable instead of Table tag , but no luck, table does not update.
Any ideas what to do in RTable function to force the update on Table?
Or any other idea how to solve this?
actually, the problem is that rowClassName is a function and mobx can only react to property changes.
So what we did is to pass the selectedId as property, so that mobx detects the change and rerenders the component:
export interface RTableProperties<RecordType extends object = any> extends TableProps<RecordType> {
selectedRecordId: string | undefined
}
export function RTable<RecordType extends object = any>(rTableProps: RTableProperties<RecordType>): JSX.Element {
const rTable = <Table {...rTableProps} />
return rTable
}
I have a custom component that allows for editing a user. It displays a dialog which can be fed an existing user. Or not. It has the markup:
<button mat-button (click)="openUserDialog()">Edit</button>
and the controller:
#Component({
selector: 'app-user-edit',
templateUrl: './user-edit.component.html',
})
export class UserEditComponent implements OnChanges {
#Input() existingUser: User;
#Output() userEditedEvent: EventEmitter<User> = new EventEmitter<User>();
userDialogRef: MatDialogRef<UserDialogComponent>;
constructor(
private matDialog: MatDialog,
private userService: UserService
) { }
ngOnChanges() {
}
openUserDialog() {
this.userDialogRef = this.matDialog.open(UserDialogComponent, {
hasBackdrop: false,
data: {
user: this.existingUser
}
});
this.userDialogRef
.afterClosed()
.subscribe(user => {
// TODO validate the edited user
if (user) {
if (this.existingUser) {
user.id = this.existingUser.id;
this.userService.fullUpdate(user)
.subscribe(updatedUser => {
this.userEditedEvent.emit(updatedUser);
// TODO Add a hint that the user has been added
});
} else {
this.userService.add(user)
.subscribe(addedUser => {
this.userEditedEvent.emit(addedUser);
// TODO Add a hint that the user has been updated
});
}
}
});
}
}
The component is then being used in the users list page, once on top of the list to add a new user, with the markup:
<app-user-edit (userEditedEvent)="refreshList($event)"></app-user-edit>
and on each row of the list to edit the user, with the markup:
<app-user-edit [existingUser]="user" (userEditedEvent)="refreshList($event)"></app-user-edit>
The trouble is that the view displays the Edit label both to add and to edit a user.
How could I have a custom Add label on top of the list, and another Update label for each user ?
I feel like I may have overengineered the whole thing.
You can add another #Input parameter say label and pass the value of the label from the mark up.
export class UserEditComponent implements OnChanges {
#Input() existingUser: User;
#Input() label: string = "Edit" // set default to EDIT. If preferred can initialised to empty.
Mark up for ADD:
<app-user-edit (userEditedEvent)="refreshList($event)" label="ADD"></app-user-edit>
Mark up for EDIT:
<app-user-edit [existingUser]="user" (userEditedEvent)="refreshList($event)" label="EDIT"></app-user-edit>
Also, bind parameter label in view where it needs to be shown.
I'm trying make to work my validation. I have data posted to controller in the format like this:
[
'property' => 'value',
'nested_property' => [
'property' => 'value',
// ...
]
]
I have divided fields/filters and form into different classes and just gather it together in the Form's controller that looks like that:
public function __construct($name, $options)
{
// ...
$this->add(new SomeFieldset($name, $options));
$this->setInputFilter(new SomeInputFilter());
}
But it doesn't work properly, looks like it just ignores nested array (or ignores everything). What have I missed?
Thank you.
You need to set up your inputfilter like the way you've setup your forms including the fieldsets if you use the InputFilter class.
So when you've got a structure like:
MyForm
1.1 NestedFieldset
1.2 AnotherFieldset
Your inputfilters need to have the same structure:
MyFormInputFilter
1.1 NestedFielsetInputFilter
1.2 AnotherFieldsetInputFilter
Some example code:
class ExampleForm extends Form
{
public function __construct($name, $options)
{
// handle the dependencies
parent::__construct($name, $options);
$this->setInputFilter(new ExampleInputFilter());
}
public function init()
{
// some fields within your form
$this->add(new SomeFieldset('SomeFieldset'));
}
}
class SomeFieldset extends Fieldset
{
public function __construct($name = null, array $options = [])
{
parent::__construct($name, $options);
}
public function init()
{
// some fields
}
}
class ExampleInputFilter extends InputFilter
{
public function __construct()
{
// configure your validation for your form
$this->add(new SomeFieldsetInputFilter(), 'SomeFieldset');
}
}
class SomeFieldsetInputFilter extends InputFilter
{
public function __construct()
{
// configure your validation for your SomeFieldset
}
}
So the important part of configuring your inputFilter for these situations is that you need to reuse the name of your fieldset when using: $this->add($input, $name = null) within your InputFilter classes.
In Dart I am attempting something like:
<element name="x-facet-select" constructor="SelectOptions" extends="div">
<template>
<div>
<select bind-value="str" on-click="update()" on-load="init()" id="outputitems" multiple="multiple">
I can't get the on-load (or onload, or anything) method to run in the SelectOptions call. It's jus a simple print Hello World line to console as a test.
Is there a way in Dart's WebUI to invoke a method on the initial loading of an element?
If you want to run code after the user changes the drop down value:
<select id="list" on-change="selectionChanged($event)">
<option>one</option>
<option>two</option>
<option>three</option>
</select>
class SelectOptionsComponent extends WebComponent {
selectionChanged(Event e) {
print(__list.value);
}
}
That would be all.
Update: Looks like you also want to run some code after the component is ready, try inserted():
class SelectOptionsComponent extends WebComponent {
selectionChanged(Event e) {
print(__list.value);
}
inserted() {
// populate __list here.
(__list as OListElement).innerHtml = '<option>bar</option>'; // Just an example.
}
}
I'm trying to develop a custom component that will need to call a method from the backingbean to get some data from the bb (this will be called in the decode phase after a certain Ajax call) with one parameter (it will come in the ajax call).
The problem I'm having is that I define the attribute as a MethodExpression (in the taglibrary and the component), I get the Ajax post, decode the parameter and when I try to get the Method binding from the component I get the following error:
javax.el.PropertyNotFoundException: /easyFaces.xhtml #19,151
dataSource="#{theBean.loadDataFromSource}": The class
'ar.com.easytech.faces.test.homeBean' does not have the property
'loadDataFromBean'.
Here is the relevant code.. (and please let me know if this is not the correct way to do this..)
taglib:
<attribute>
<display-name>Data Source</display-name>
<name>dataSource</name>
<required>true</required>
<type>javax.el.MethodExpression</type>
<method-signature>java.util.List theDataSource(java.lang.String)</method-signature>
</attribute>
Component definition:
public class Autocomplete extends HtmlInputText implements ClientBehaviorHolder
...
public MethodExpression getDataSource() {
return (MethodExpression) getStateHelper().eval(PropertyKeys.dataSource);
}
public void setDataSource(MethodExpression dataSource) {
getStateHelper().put(PropertyKeys.dataSource, dataSource);
}
and finally the rendered method that generates the error:
private List<Object> getData(FacesContext context, Autocomplete autocomplete, String data) {
Object dataObject = null;
MethodExpression dataSource = autocomplete.getDataSource();
if (dataSource != null) {
try {
dataObject = dataSource.invoke(context.getELContext(), new Object[] {data});
return convertToList(dataObject);
} catch (MethodNotFoundException e) {
logger.log(Level.INFO,"Method not found: {0}", dataSource.getExpressionString() );
}
}
return null;
}
Here is the method from the BB
public List<String> autcompleteFromSource(String param) {
List<String> tmpData = new ArrayList<String>();
tmpData.add("XXA_TABLE_A");
tmpData.add("XXA_TABLE_B");
tmpData.add("XXA_TABLE_C");
return tmpData;
}
And the .xhtml with the component
<et:autocomplete id="autoc" minLength="3" delay="500" value="#{easyfacesBean.selectedValue}" dataSource="#{easyfacesBean.autcompleteFromSource}" />
The thing is if I define a method getAutocompleteFromSource() it recognised the method and the error changes to can't convert list to MethodExpression, so evidently it is simply interpreting the autocompleteFromSource as a simple property and not a method definition, is this even the correct way to call method from BB? (giving that it's not an actual action nor validation )
I found the solution for this, as it turns out you also need to define a "Handler"to define the Method Signature, so I created the handler and added to the taglib and everything started to work fine..just for reference.. here is the handler..
Regards
public class AutocompleteHandler extends ComponentHandler {
public AutocompleteHandler(ComponentConfig config) {
super(config);
}
protected MetaRuleset createMetaRuleset(Class type) {
MetaRuleset metaRuleset = super.createMetaRuleset(type);
metaRuleset.addRule(new MethodRule("dataSource", List.class, new Class[] { String.class }));
return metaRuleset;
}
}