antd Table with switch component - antd

Is it possible to get row information by switching the switch in ant design table?
https://codesandbox.io/s/mmvrwy2jkp

Yes, the second argument of the render function is the record.
you can do this
{
title: 'switch',
dataIndex: 'age',
key: 'age',
render: (e, record) => (< Switch onChange={() => handleSwitchChange(record)} defaultChecked={e} />)
}

This is how I dealed with the switch component on each row item when using Ant design. Maybe this could give you some hints.
Table Columns
const COLUMN =
{
title: 'Status',
key: 'status',
dataIndex: 'status',
// status is the data from api
// index is the table index which could be used to get corresponding data
render: (status, record, index) => {
const onToggle = (checked) => {
status = checked;
onActiveUser(index, status);
};
return (
<Space>
<Switch defaultChecked={status} onChange={onToggle} />
</Space>
);
},
},
const onActiveUser = (index, status) => {
axios.patch({ id: users[index].id }, { is_active: status })
.then((response) => {
console.log(response);
})
.catch(() => {
console.log('Failed!');
});
};

Related

Is there a way to make api call when expanding table to show nested table?

In Ant Nested table - When expanding a row, I want to make an api call and get the data to show the nested table.
The function expandedRowRender, expects to return the nested table, it does not accept a promise.
How can I show a nested Ant table using ajax call?
I have tried to recreate the scenario for reference.
import ReactDOM from "react-dom";
import "antd/dist/antd.css";
import "./index.css";
import { Table } from "antd";
import reqwest from "reqwest";
const nestedColumns = [
{
title: "Name",
dataIndex: "name",
sorter: true,
render: name => `${name.first} ${name.last}`,
width: "20%"
},
{
title: "Gender",
dataIndex: "gender",
filters: [
{ text: "Male", value: "male" },
{ text: "Female", value: "female" }
],
width: "20%"
},
{
title: "Email",
dataIndex: "email"
}
];
class App extends React.Component {
state = {
data: []
};
fetch = (params = {}) => {
console.log("params:", params);
reqwest({
url: "https://randomuser.me/api",
method: "get",
data: {
results: 10,
...params
},
type: "json"
}).then(data => {
return (
<Table
columns={nestedColumns}
dataSource={data.results}
pagination={false}
/>
);
// this.setState({
// data: data.results
// });
});
};
expandedRowRender = () => {
this.fetch();
return <table columns={nestedColumns} dataSource={this.state.data} />;
};
render() {
const columns = [
{ title: "Name", dataIndex: "name", key: "name" },
{ title: "Platform", dataIndex: "platform", key: "platform" },
{ title: "Version", dataIndex: "version", key: "version" }
];
const data = [
{
key: 1,
name: "Screem",
platform: "iOS",
version: "10.3.4.5654"
}
];
return (
<Table
columns={columns}
dataSource={data}
pagination={false}
expandedRowRender={this.expandedRowRender}
/>
);
}
}
ReactDOM.render(<App />, document.getElementById("container"));
I try my level best to answer your question. Here is the reduced type of code and you can get an idea of how to do that.
In state,
state = {
data: null,
loading: false,
};
Here is your function to make API call,
fetch = (expanded, record) => {
axios.get(`put your api to load nested table`)
.then(res => {
const data = res.data;
this.setState({
...this.state.data,
data,
loading: true
})
}).catch(error => {
console.log(error, "error")
})
}
After that,
expandedRowRender=() => {
if(this.state.loading){
const nestedTableData = this.state.data.map(row => ({
key: row.id,
Id: row.id,
name: 'test',
gender: 'gender',
}))
const nestedColumns = [
{ title: "Name", dataIndex: "name", key: "name" },
{ title: "Gender", dataIndex: "gender", key: "gender" },
];
return <Table columns={nestedColumns} dataSource={nestedTableData } pagination={false} />
}
};
And put following code below return
<Table
className="components-table-demo-nested"
columns={columns}
dataSource={tableData}
expandable={{
expandedRowRender: this.expandedRowRender,
rowExpandable: record => true,
onExpand: this.fetch
}}
/>
I hope it may help you and let me know if it does. :)

VictoryPie click single series of chart at a time

I am using VictoryPie on react native (victory-native). My goal is to be able to change the color of one slice of the pie chart onClick (onPress). At any one time the color of only a single slice should be changed to my highlight color.
Using the events prop, I am able to change the color of a slice onPress, but not able to reset it upon clicking on another slice using code like this:
onPress: () => {
return [
{
target: 'data',
mutation: (props) => {return {style: {...props.style, fill: #000000}}}
}
}
Ideally I would like to use the additional eventKey prop to be able to return {style: undefined} for the other slices. But I am not able to determine how to get the array of other elements for the eventKey prop. The onPress does not have any argument stating the index or element. Is there some other way that I can know which item was clicked inside the onPress function?
Thanks for the help in advance!
I was also stuck on the same thing. Here's the code of how I solved that issue. Hope this helps 😊.
<VictoryPie
standalone={false}
labelRadius={({ innerRadius }) => innerRadius + 25}
labelPlacement={({ index }) => {
return "perpendicular";
}}
labelComponent={
<VictoryLabel
style={[
{
fill: Colors.white,
fontSize: 15,
fontFamily: "Bold",
},
]}
/>
}
style={{
data: {
fillOpacity: 1,
stroke: Colors.white,
strokeWidth: 5,
fill: ({ datum, index }) => {
let data = emotions.map((item, index) => {
return item;
});
if (
selectedEmotion.emotion === data[index].emotion_name
) {
return "tomato";
}
return data[index].background_color;
},
},
}}
events={[
{
target: "data",
eventHandlers: {
onPressOut: () => {
return [
{
target: "data",
mutation: (props) => {
let { x, description, id } = props.datum;
setSelectedEmotion({
emotion_id: id,
emotion: x,
description: description,
});
},
},
];
},
},
},
]}
data={EmotionsData}
width={450}
height={450}
colorScale={graphicColorData}
innerRadius={100}
/>
Didn't find it in documentation but searching online, see that you can use props as an argument in the onClick/onPress
you can just first check fill props like this in the mutation object
mutation: (props) => {
const fill = props.style && props.style.fill;
return fill === "#7CFC00" ? null : { style: { fill: "#7CFC00" } };
}

Binding value on input text in react native doesn't let me write anymore

I got the following input text on a Child Component:
<Input
placeholder={ i18n.t('searchSomeone') }
value={ this.props.searchText }
onChangeText={ this.props.onSearch }
defaultValue={''}/>
This is the way , I'm passing the variable and onChangeText handler:
<ChildComponent
onSearch={ this._onSearch }
searchText={ this.state.searchText }>
</ChildComponent>
And this is the _onSearch() function:
componentWillMount: function() {
this._onSearch = _.debounce((text) => {
this.setState({ refreshing : true }, () => {
if(text.length === 0) {
this.setState({ filteredSearch: false }, () => {
this.getAllReports();
})
}else{
this.setState({
page: 1,
refreshing: true,
reports: [],
filteredSearch: true
}, () => {
this.getReportsBySearchString();
})
}
})
}, 1000);
},
I wanted to bind this input text value, because when I do a pull up to refresh, i just want to set the text to empty string.
_onRefresh: function() {
this.setState({
filteredSearch: false,
searchText: ''
}, () => {
this.getAllReports();
})
},
But the problem is that with this implementation, whenever I try to type in the text input, it doesn't type anything.
What am I missing?
It looks like you are not saving the input value in this.state.searchText. That's the reason why the input value is always ''.
this._onSearch = _.debounce((text) => {
this.setState({
refreshing : true,
searchText: text // <-- Here
}, () => {
if(text.length === 0) {
this.setState({ filteredSearch: false }, () => {
this.getAllReports();
})
}else{
this.setState({
page: 1,
refreshing: true,
reports: [],
filteredSearch: true
}, () => {
this.getReportsBySearchString();
})
}
})
}, 1000);
Edit
You can try debounce the callback function you are passing to setState, it is not tested so I'm not sure if it is going to work.
It should be something like this
this._onSearch = (text) => {
this.setState({
refreshing : true,
searchText: text
}, this._callback)
this._callback = _.debounce(() => {
const text = this.state.searchText;
if(text.length === 0) {
...
}
}, 1000);

Yii2 Autocomplete Widget Categories

JQuery's Autocomplete supports categories in the autocomplete results. Like in the link below (just type the letter 'a'):
https://jqueryui.com/resources/demos/autocomplete/categories.html
Yii2's jQuery Autocomplete widget has a source parameter that can take in an array for the results of the Autocomplete. But when I give it a multi-dimensional array, trying to get categories like the link above, it breaks the Autocomplete. See below:
AutoComplete::widget([
'name' => 'search_terms',
'options' => [
'style' => 'width:100%;',
],
'clientOptions' => [
'source' => ['NA' => ['USA', 'CAN'], 'EUR' => ['RUS', 'SPN']],
],
])
How do I get categories working in Yii2's Autocomplete widget?
This type of widgets is just a wrapper of Javascript plugin allowing you to register it using PHP code (configure properties using PHP arrays instead of Javascript objects, etc.). If you investigate the sources of AutoComplete widget and parent classes, you will not find any special processing of source property. That means you need to follow jQuery UI plugin docs, click the "view source" link here to show code. JS part looks like this:
<script>
$( function() {
$.widget( "custom.catcomplete", $.ui.autocomplete, {
_create: function() {
this._super();
this.widget().menu( "option", "items", "> :not(.ui-autocomplete-category)" );
},
_renderMenu: function( ul, items ) {
var that = this,
currentCategory = "";
$.each( items, function( index, item ) {
var li;
if ( item.category != currentCategory ) {
ul.append( "<li class='ui-autocomplete-category'>" + item.category + "</li>" );
currentCategory = item.category;
}
li = that._renderItemData( ul, item );
if ( item.category ) {
li.attr( "aria-label", item.category + " : " + item.label );
}
});
}
});
var data = [
{ label: "anders", category: "" },
{ label: "andreas", category: "" },
{ label: "antal", category: "" },
{ label: "annhhx10", category: "Products" },
{ label: "annk K12", category: "Products" },
{ label: "annttop C13", category: "Products" },
{ label: "anders andersson", category: "People" },
{ label: "andreas andersson", category: "People" },
{ label: "andreas johnson", category: "People" }
];
$( "#search" ).catcomplete({
delay: 0,
source: data
});
} );
</script>
As you can see, you are passing categories wrong. Try this instead:
'source' => [
['label' => 'USA', 'category' => 'NA'],
['label' => 'CAN', 'category' => 'NA'],
['label' => 'RUS', 'category' => 'EUR'],
['label' => 'RUS', 'category' => 'SPN'],
],
Also for this case maybe you need to include additional JS (above plugin registration) to completely reproduce example.

Passing Braintree nonce to ruby on rails controller

i am currently using braintree hosted fields, to embed the credit cards into my app. i am looking at how i pass the payment nonce from the view to the controller. the javascript i have seems to be triggering the braintree api and returning a nonce to my alert but i just need to now push this through to the controller to execute the final piece of the code
within the controller create method i have
def create
result = Braintree::PaymentMethod.create(
:customer_id => current_user.customer_cim_id,
:payment_method_nonce => nonce_from_the_client,
:cardholder_name => "#{current_user.first_name} #{current_user.last_name}",
:options => {
:make_default => true,
:fail_on_duplicate_payment_method => true
}
)
new view
- title t('.title')
= form_for(#payment_method, :url => myaccount_payment_methods_path(#payment_method), :html => {:id => 'cardForm'}) do |f|
= render :partial => 'form', :locals => {:f => f}
/ Load Hosted Fields component.
%script{:src => '//js.braintreegateway.com/web/3.0.0-beta.10/js/hosted-fields.min.js'}
form view
.mdl-grid
.panel
%header.panel__header
%h1 Card Payment
.panel__content
.textfield--float-label
%label.hosted-field--label{:for => "card-number"}
%i.material-icons credit_card
Card Number
#card-number.hosted-field
.textfield--float-label
%label.hosted-field--label{:for => "expiration-date"}
%i.material-icons date_range
Expiration Date
#expiration-date.hosted-field
.textfield--float-label
%label.hosted-field--label{:for => "cvv"}
%i.material-icons lock
CVV
#cvv.hosted-field
%footer.panel__footer
= f.submit class: 'pay-button', id: 'button-pay', disabled: true
application.js
var form = document.querySelector('#cardForm');
var submit = document.querySelector('input[type="submit"]');
braintree.client.create({
authorization: 'sandbox_92dswc7q_mbmb637xwpzgxbrd'
}, function (err, clientInstance) {
if (err) {
console.error(err);
return;
}
// Create input fields and add text styles
braintree.hostedFields.create({
client: clientInstance,
styles: {
'input': {
'color': '#282c37',
'font-size': '16px',
'transition': 'color 0.1s',
'line-height': '3'
},
// Style the text of an invalid input
'input.invalid': {
'color': '#E53A40'
},
// placeholder styles need to be individually adjusted
'::-webkit-input-placeholder': {
'color': 'rgba(0,0,0,0.6)'
},
':-moz-placeholder': {
'color': 'rgba(0,0,0,0.6)'
},
'::-moz-placeholder': {
'color': 'rgba(0,0,0,0.6)'
},
':-ms-input-placeholder ': {
'color': 'rgba(0,0,0,0.6)'
}
},
// Add information for individual fields
fields: {
number: {
selector: '#card-number',
placeholder: '1111 1111 1111 1111'
},
cvv: {
selector: '#cvv',
placeholder: '123'
},
expirationDate: {
selector: '#expiration-date',
placeholder: '10 / 2019'
}
}
}, function (err, hostedFieldsInstance) {
if (err) {
console.error(err);
return;
}
hostedFieldsInstance.on('validityChange', function (event) {
// Check if all fields are valid, then show submit button
var formValid = Object.keys(event.fields).every(function (key) {
return event.fields[key].isValid;
});
if (formValid) {
$('.pay-button').prop("disabled", false);
} else {
$('.pay-button').prop("disabled", true);
}
});
hostedFieldsInstance.on('empty', function (event) {
$('header').removeClass('header-slide');
$('#card-image').removeClass();
$(form).removeClass();
});
hostedFieldsInstance.on('cardTypeChange', function (event) {
// Change card bg depending on card type
if (event.cards.length === 1) {
$(form).removeClass().addClass(event.cards[0].type);
$('#card-image').removeClass().addClass(event.cards[0].type);
$('header').addClass('header-slide');
// Change the CVV length for AmericanExpress cards
if (event.cards[0].code.size === 4) {
hostedFieldsInstance.setPlaceholder('cvv', '1234');
}
} else {
hostedFieldsInstance.setPlaceholder('cvv', '123');
}
});
submit.addEventListener('click', function (event) {
event.preventDefault();
hostedFieldsInstance.tokenize(function (err, payload) {
if (err) {
console.error(err);
return;
}
// This is where you would submit payload.nonce to your server
alert('Got a nonce: ' + payload.nonce);
// If this was a real integration, this is where you would
// send the nonce to your server.
console.log('Got a nonce: ' + payload.nonce);
});
}, false);
});
});
Full disclosure: I work at Braintree. If you have any further questions, feel free to contact support.
Right after your alert line in application.js, you will want to send a request to your server that contains the payment method nonce. For example you can do this with Ajax:
$.ajax({
type: "POST",
url: your_payment_url,
data: {"payment_method_nonce":payload.nonce}
});
Then within your Ruby on Rails controller, you can call Transaction.sale using the payment method nonce in the request to complete the transaction.
For more information on hosted fields, please check out this link.
Edit on Vault question:
If you're using Vault, you can charge users without needing a payment nonce each time. After creating the customer (either through the control panel or through Customer.create, you can retrieve a payment_method_token directly through the payment_methods attribute of the Customer object. To charge the user later, retrieve their payment_method_token on your server and call Transaction.sale, passing in the payment_method_token.
result = Braintree::Transaction.sale(
:amount => "your_amount",
:payment_method_token => "payment_method_token"
)

Resources