Passing child's events to a parent - reactjs

I am enhancing a textarea with autocomplete functionality like this:
<MentionAutocomplete ref="autocomplete">
<Textarea ref="editor"/>
</MentionAutocomplete>
The idea is that MentionAutocomplete can use any thing like textarea or input in itself and still work.
This works nicely and its achieved by the autocomplete listening to keyboard events like this:
<div
className="MentionAutocomplete"
onKeyDown={this.handleKey}
onKeyUp={this.handleKeyUp}
>
{this.props.children}
{this.renderAutocomplete()}
</div>
But I recently ran into an issue, where the autocomplete complains that field.value is undefined. I am assuming that the Textarea component might be doing something, or there might be a browser extension messing with it.
So ideally I would like to do something like this:
var self = this;
<MentionAutocomplete ref="autocomplete">
<Textarea ref="editor" onKeyUp={(event) => self.refs.autocomplete.keyUp(event) } />
</MentionAutocomplete>
But I am wondering, is this the right approach? Is there a better way?

If I understand your issue correctly, you can define the event handler on the parent, and pass it through to the child:
<div className="MentionAutocomplete">
{React.cloneElement(this.props.children {handleEvent: this.handleEvent})}
</div>
handleEvent here is a function you define on the parent where you can pass the event or whatever and is available on the child through this.props.
Another approach that seems a good fit for what you're trying to create would be to create a higher order component which essentially wraps a component with another to add functionality.

Related

Can I name elements within components anything I want?

If I have lets say App component, like this
const App = () => {
return(
<div>
<p>hello world</p>
</div>)}
can I name div whatever i want like I did below? It works in the browser just fine but Im not sure,
const App = () => {
return(
<whatever>
<p>hello world</p>
</whatever>)}
Yes You can. But:
if You want to work with React, don't capitalize the name of div like this: <Whatever>, because it will seems to React that this is an another Component.
And when Your project gets bigger, it will start to get more complicated, so its a good practice to write tags by they names.
Yes you can name them whatever you like, people often do it so the markup is a bit more friendly to read and understand. For example Appcues injects their widget into your website and if you look at the markup for it, it has elements like <appcues/>.
Just check the browser support for these custom HTML tags, I think most major ones do support it but just to be safe.

What happens if you set role = "" on an HTML element?

I am using ReactJS to create a generic wrapper component. I want to pass in role as a propType and on my rendered div have something like <div role={role}>.
My question is, what if a role isn't passed in and I end up with <div role="">? Will that mess up screen readers, etc.?
I don't want to make it a required prop because this is just a generic wrapper div and not all elements will have a role.
No, it shouldn't mess anything up.
As far as a browser is concerned, there's not really any difference between <div role=""> and <div>

Angular 2: Is it possible to use the same parent component with different child components?

I would like to know if is it possible to define a parent component without specifying which child component to use?
Normally i would create a parent component and use the selector of the child component in the html file
parent-component-1.html:
//some logic
<child-component-1-selector></child-component-1-selector>
//some logic
If i follow this approach i have to define which kind of child component i wanna use. But if i wanna use the parent component multiple times with different child components, i have to copy the logic part and create separate parent-components:
parent-component-1.html:
//some logic
<child-component-1-selector></child-component-1-selector>
//some logic
parent-component-2.html:
//some logic (same as above)
<child-component-2-selector></child-component-2-selector>
//some logic (same as above)
I don't like the approach because i would generate code duplicates. Is there a way to define the parent-component without specifying which child component to render and just 'pass' the child component as an argument?
current approach,
grand-parent-component.html:
<parent-component-1></parent-component-1>
<parent-component-2></parent-component-2>
suggested approach,
grand-parent-component.html:
<parent-component-selector [childcomponent] = "child-component-1"></parent-component-selector>
<parent-component-selector [childcomponent] = "child-component-2"></parent-component-selector>
I hope i have made my self clear about my 'problem'. Maybe you guys can help me and give suggestions about best practices
It sounds like you want to be able to do something like:
<my-custom-panel>
<here-is-one-inner-component>
</my-custom-panel>
And then in another place,
<my-custom-panel>
<some-other-component>
</my-custom-panel>
If i'm reading you right, then you're basically looking at using Angular's content projection.
So, in my example above, I'd write my-custom-panel component to look like this:
#Component({
selector: 'my-custom-panel',
template: `
<div class="wrapper">
<h1>My Heading</h1>
<ng-content></ng-content>
</div>
`
})
export class ....
The trick is that <ng-content> tag, which acts as a marker in the component's template. When using my-custom-panel in another template, any content that appears within the my-custom-panel tag will get projected right next to that <ng-content> tag.
Hopefully, an example will make things clearer. So, in the case of my first example, where the template using my-custom-panel is:
<my-custom-panel>
<here-is-one-inner-component>
</my-custom-panel>
That will get transformed into:
<div class="wrapper">
<h1>My Heading</h1>
<ng-content></ng-content>
<here-is-one-inner-component>
</div>
Is that what you're looking for?

How to respond to onChange event for a dropdown in angularify

I'm trying to use angularify in a project, but I'm facing the given problem:
I'm not able to get my onChange function called when a dropdown value changes. I have a second dropdown box which the listed values depends upon the first one.
How can I achieve the intended behavior with angularify?
I was looking, debugging and trying, and looks like I will not be able to do this because de dropdown directive writes a bunch of div's to my html. There is no select elmeent in any place of the document. How will a div element fire a onChange event?
Here is my markup:
Parent select
<dropdown title="Selecione" class="col-6" ng-model="novoProcedimento.procedimento" ng-change="buscarLocaisExecucao(novoProcedimento.procedimento)">
<dropdown-group class="meudropdown" title="proc.nome" value="proc.nome" ng-repeat="proc in procedimentosPermitidos">{{proc.nome}}</dropdown-group>
</dropdown>
Child select - Depends on parent's selection
<dropdown title="Selecione" id="dente-regiao" class="col-5" ng-model="novoProcedimento.local" ng-change="buscarFaces(novoProcedimento.procedimento, novoProcedimento.local)">
<dropdown-group title="local" value="local" ng-repeat="local in locaisExecucao">{{local.descricao}}</dropdown-group>
</dropdown>
Controller - Intendend to be fired on parent's change.
$scope.buscarLocaisExecucao = function (procedimento){
selecaoProcedimentoService.buscarLocaisExecucao(procedimento)
.then(function(locaisExecucao) {
$scope.locaisExecucao = locaisExecucao;
});
}
Am I using the wrong framework? Am I missing something?
Thank you.

how to go from angular event to jquery selector

I know this is bad design but would like to introduce angular to a current project. I would like sayHello to be able to determine whether the element has the class 'is-a-favorite'
<div ng-click="sayHello(29, $event)" class="is-a-favorite" data-type="location" data-global-id="29" data-make-disappear="false"> </div>
$scope.sayHello=function(global_id,event){
//var selector=???
if(selector.hasClass('is-a-favorite')){
console.log("this is-a-favorite");
}
};
How would (or could) I get a reference to current DOM element to query via hasClass?
thx
The clicked element is available as $event.target, so you could check $($event.target).attr('class') or something similar.
EDIT: actually, what you'd want is to check $($event.target).hasClass('is-a-favorite')

Resources