How to call function within component property? - reactjs

When I try to call a method or set a state inside a property of a component in this case Sortablejs the method returns an undefined error.
<Sortable options={{
animation: 150,
onAdd: function(/**Event*/ evt) {
this.testFunction();//this doesnt seem to work??
},
group: {
name: "clone2",
pull: true,
put: true
}
}}
className="block-list A"
tag="ul"
>
{cloneControlledTarget}
</Sortable>
<Sortable
options={{
animation: 150,
sort: false,
group: {
name: "clone2",
pull: "clone",
put: false
}
}}
className="block-list"
tag="ul"
>
{cloneControlledSource}
</Sortable>

I think issue is in the following code. Use arrow function instead of traditional anonymous function
onAdd: function(/**Event*/ evt) {
this.testFunction();//this doesnt seem to work??
}
Use like this
onAdd: (/**Event*/ evt) => {
this.testFunction();
}
This should work if testFunction is available in your component.

You are passing an object
{
animation: 150,
onAdd: function(/**Event*/ evt) {
this.testFunction();
},
group: {
name: "clone2",
pull: true,
put: true
}
}
to the options attribute. So inside the function onAdd the value of "this" refers to the object properties. Since there is no testFunction inside the object, it will throw a reference error. Use arrow function instead.
onAdd: () => { this.testFunction() }

Related

Is it possible to render a component at the bottom of viewport when testing in react testing library?

I need to test how the select component behaves when it is positioned at the bottom of a page. When it is 1) at the top of the page - it opens dropdown to the bottom, and when it is 2) at the bottom of the page it opens dropdown to the top. I have no problem with testing its first behaviour, but I cannot test the second.
I tried to test it like this:
document.body.style.height = '500px'
const { container } = render(<Select {...requiredProps} />)
container.firstChild.style.position = 'fixed'
container.firstChild.style.bottom = '0'
fireEvent.click(screen.getByTestId('dropdown-container'))
expect(screen.getByTestId('dropdown-items')).toHaveStyle(stripSpaces('bottom: 100%'))
But still I cannot simulate the proper behaviour.
I tried also below:
Object.defineProperty(window, 'innerHeight', { writable: true, configurable: true, value: 500 })
render(<Select {...requiredProps} />)
fireEvent.scroll(window, { target: { scrollY: 500 } })
fireEvent.click(screen.getByTestId('dropdown-container'))
expect(screen.getByTestId('dropdown-items')).toHaveStyle(stripSpaces('bottom: 100%'))
And also below:
Object.defineProperty(window, 'innerHeight', { writable: true, configurable: true, value: 500 })
render(<Select {...requiredProps} style={{ position: 'fixed', bottom: '0' }} />)
fireEvent.click(screen.getByTestId('dropdown-container'))
expect(screen.getByTestId('dropdown-items')).toHaveStyle(stripSpaces('bottom: 100%')
The problem is that to open dropdown at the top, I use getBoundingClientRect() on select, to find out how far it is from top and bottom. And in jest testing, getBoundingClientRect always returns 0 for each value - see https://github.com/jsdom/jsdom/pull/689
I try to manipulate container to give it top value of 480 but with no success.
I would first scroll all the way down and then check if some expected content or whatever appears.
you can use:
fireEvent(node: HTMLElement, event: Event)
https://testing-library.com/docs/dom-testing-library/api-events/
example:
fireEvent.scroll(scrollContainer, { target: { scrollY: 100 } });
So the answer is, yes, it is possible. It is done simply by setting the height of window first:
Object.defineProperty(window, 'innerHeight', {
writable: true, configurable: true, value: 500
})
And then by rendering the element using style property:
render(<Select {...requiredProps} style={{ position: 'fixed', bottom: 0 }} />)
I needed to position select in this way, in order to check if its items open to the top. The tests failed for me, because I calculated the condition using offsetHeight and `getBoundingClientRect() (I should have mentioned that in my question). So I needed to overwrite those values. My final test looks like this:
Object.defineProperty(window, 'innerHeight', {
writable: true, configurable: true, value: 500
})
Object.defineProperty(HTMLElement.prototype, 'offsetHeight', {
configurable: true, value: 200
})
Element.prototype.getBoundingClientRect = jest.fn().mockReturnValueOnce({ top: 400 })
render(<Select {...requiredProps} style={{ position: 'fixed', bottom: 0 }} />)
fireEvent.click(screen.getByTestId('dropdown-container'))
expect(screen.getByTestId('dropdown-items')).toHaveStyle(stripSpaces('bottom: 100%'))

custom filter ag grid react

I was trying to implement a custom DropDown filter in ag grid using React.
The link I followed is link
I was able to create the filter, however the filter doesnot appear by default. As a user, we need to click the 3 arrow icon next to the column header and then the filter appears.
Is there a way to display the custom filter dropDown by default?
I hope Floating filters can help you here.
Check this example in ag-grid documentation
filter: "agNumberColumnFilter",
floatingFilterComponent: "sliderFloatingFilter",
floatingFilterComponentParams: {
maxValue: 5,
suppressFilterButton: true
},
The example shows sliderFloatingFilter, to make it a dropdown filter, I think you need to create custom component for it.
Have a look at how ag-grid team has made TextFloatingFilterComp, DateFloatingFilterComp, NumberFloatingFilterComp etc. on GitHub code
Hope this helps.
I achieved dropdown/enum filter using this column configuration. I my case, I was trying to add a boolean filter.
Here is complete example
https://codesandbox.io/s/ag-grid-react-enum-filter-q4er8?file=/src/App.js:1572-1599
const getEnumColumnParams = (enumMap) => {
return {
cellRenderer: (params) => {
if (!params.data) return "";
const { value } = params;
return enumMap[value];
},
filterParams: {
buttons: ['reset', 'apply'],
closeOnApply: true,
filterOptions: [
"empty",
...Object.keys(enumMap).map(key => {
return {
displayKey: key,
displayName: enumMap[key],
test: function (filterValue, cellValue) {
return cellValue === true;
},
hideFilterInput: true,
};
})
],
suppressAndOrCondition: true,
},
};
};
const boolEnum = {
true: 'Yes',
false: 'No'
};
const colorEnum = {
'#ff00000': 'Red',
'#00ff00': 'Green',
'#0000ff': 'Blue',
};
const columnDefs = [
{
field: 'available',
...getEnumColumnParams(boolEnum),
},
{
field: 'color',
...getEnumColumnParams(colorEnum),
}
];
Or you can create column types and assign type: 'boolColumn' etc in column definition like I did in above codesandbox example

console.log this.props show undefined but renders correctly on react redux page

I have a very strange error in react redux project. I have payload
const req = {
setcolor:false,
hours:2,
searchterm:'',
dropdownvalue:1,
dropdownvaluetwo:1,
rooms:[
'private-messages',
'project2',
'project3',
'project4',
'project5',
'project6',
'project7',
'project8',
'project9'
],
chatrooms:[
{
key:1,
color:false,
name:'private-messages'
},
{
key:2,
color:false,
name:'project2'
},
{
key:3,
color:false,
name:'project3'
},
{
key:4,
color: false,
name:'project 4'
},
{
key:5,
color: false,
name:'project 5'
},
{
key:6,
color: false,
name:'project 6'
},
{
key:7,
color: false,
name:'project 7'
},
{
key:8,
color: false,
name:'project 8'
},
{
key:9,
color: false,
name:'project 9'
}
],
projectchat:[
{
projectname:'private-messages',
chatmessages:[
{
username: 'ankur',
message: 'whatsup'
},
{
username: 'ankur',
message: 'kya hal hai'
}
]
},
{
projectname:'project2',
chatmessages:[
{
username: 'ankur',
message: 'whatsup'
},
{
username: 'ankur',
message: 'kya hal hai'
}
]
}
]
};
Now, on front end , If i use
<div>
{this.props.projectlist.hours}
</div>
I see correct value on page which is 2. But, if i do
<div>
{this.props.projectlist.chatrooms[0].name}
</div>
It throws me an error as property undefined.
Now, if i do
<div>
{console.log("this.props",this.props.projectlist}
{this.props.projectlist.chatrooms[0].name}
</div>
This console log shows me undefined. This is really strange error. Either, I am overlooking something very simple or this quirk is related to redux internal working. Can someone help me out?
I am assuming you are getting this req object from an endpoint, or from some kind of async. If this is the case, then there is a point in time when this.props.projectlist is not yet your request object, therefor this.props.projectlist.chatrooms will be undefined, which mean there is no index 0 for chatrooms and so on.
You can solve this by making sure your values are in place before you try and use them.
Something along the lines of
if (this.props.projectlist && this.props.projectlist.chatrooms && this.props.projectlist.chatrooms[0] && this.props.projectlist.chatrooms[0].name ) {
// run my code
}
I find this solution to be longwinded and personally because I use lodash in my javascript projects you can just use lodashs' get, like so ( if you want to use lodash, of course). Alternatively you could try and make a little function to run a null coalesce for you.
if (_.get(this.props.projectlist, 'chatrooms[0].name', false ) {
// run my code
}
(the third arg here is a a value if any of the nodes are not found/undefined. I've set it to false to pass over this if statement, because our data is not there)
The above examples are for JS, If you want to keep it all inside the jsx you can use the && trick as well, something like :
{this.props.projectlist && this.props.projectlist.chatrooms && this.props.projectlist.chatrooms[0] && this.props.projectlist.chatrooms[0].name &&
<div>
{this.props.projectlist.chatrooms[0].name}
</div>
}
TL:DR - your props probably aren't there the very first render when the console.log is running.

Sencha touch Animation's after handler not taking a function

I am using Sencha touch 2.0.1.1.
In the view I am doing some animation in dragend function of a container and on this animation end I want to perform some more things, but the after handler is not taking function as handler. Here is the code
Ext.Animator.run({
element: dataview.element,
duration: 500,
autoClear : true,
easing: 'ease-in',
preserveEndState: true,
to: {
height: to_h
},
from: {
height: dataview.element.getHeight()
},
after: function() {
console.log ("After run");
}
});
This is the error I get:
Uncaught Error: [ERROR][Ext.fx.animation.Abstract#applyAfter] Invalid config, must be a valid config object Console.js:17
but this somehow works if I do like this:
Ext.Animator.run({
element: dataview.element,
duration: 500,
autoClear : true,
easing: 'ease-in',
preserveEndState: true,
to: {
height: to_h
},
from: {
height: dataview.element.getHeight()
},
after: {
fn : console.log (this)
}
});
Since I want to do bunch of things apart from just console.log so can someone suggest me right way to use this handler to execute a function which is written in-place or in the view?
Try 'onEnd:' instead of 'after:'

Call function when link inside a grid column is clicked

I need to add a click event on a link inside the grid, how's that working?
This is my grid:
Ext.define('AM.view.advertiser.List', {
extend:'Ext.grid.Panel',
alias:'widget.advertiserlist',
title:'All Advertisers',
store:'Advertisers',
columns: [
{
xtype:'gridcolumn',
dataIndex:'clientname',
text:'Clientname',
width: 200,
renderer: function(val) {
return ''+ val +'';
}
}]
});
Here is how I hacked the same exact situation, but I wanted controller to respond to the click events and I needed to extract info after the hashmark:
'myView gridpanel[ref=myGrid]':{
itemclick : function(view, model, row, rowindex, event) {
var hash = event.getTarget().hash;
if (!hash && event.getTarget().parentNode) {
hash = event.getTarget().parentNode.hash
}
if(hash) {
console.log("Control: "+hash);
//do something with the hash -> #{mydata}
}
}
}
xtype:'gridcolumn',
dataIndex:'clientname',
text:'Clientname',
width: 200,
autoEl:{
tag: 'a',
href: '',
onClick: 'nameYouFunction',
//Any methods to add here
}
You can use the following event:
http://docs.sencha.com/extjs/4.1.1/#!/api/Ext.grid.Panel-event-cellclick
And after that, you can use parameters of the event to make it work as you want

Resources