Can't get ant design field decorator to work on itself - antd

Using ant design 4. New to the framework. Wondering why the below code doesn't work:
return (
<Form
initialValues={{ foo: 1 }}
form={form}
onFinish={onFinish}
>
<Form.Item dependencies={['foo']}>
{({getFieldValue,setFieldsValue}) => {
return (
<button
type="button"
onClick={() => {
setFieldsValue({ foo: getFieldValue('foo') + 1 });
}}
>
Click Me {getFieldValue('foo')}
</button>
);
}}
</Form.Item>
</Form>
)
Obviously I'm misunderstanding something about the way ant design forms work. My actual use case is very similar - I need to render a component that accepts an onClick and updates the form.
What am I misunderstanding here? Is there any way to make something like this work?

This is a bug that was fixed in 4.17, despite any mention of it in the changelog.
Stackblitz of Bug in 4.16.13: https://stackblitz.com/edit/react-joj8ay
Stackblitz of it Fixed in 4.17: https://stackblitz.com/edit/react-emyams

Related

New to React: Why is one array treated differently than the other?

I'm working on a React app that is fed data from a Rails api. I'm currently working on a form that includes a nested association (i.e. in the model_a has many model_b's and you can create them in the same form).
The problem I'm having is that Rails expects nested association with a certain naming convention and the same field that controls how the parameter is named when its sent to rails also controls how React finds the right data when the Rails API responds.
This becomes problematic on the edit page because I want to show the models_a's (Retailers) already existing model_b's (SpendingThresholds in this case) and when I change the 'name' field to suit the rails side, React doesn't know where to look for that data anymore. When I try to pass the data directly it comes in as a different type of array and certain functions fail.
I think its easier to show than tell here so
initially I had this
<FieldArray
name="spending_thresholds"
component={renderSpendingThresholds}
/>
and data was coming through like
Object {_isFieldArray: true, forEach: function, get: function, getAll: function, insert: function…
to my React app from the Rails API, which worked, however that 'name' isn't to Rails liking (Rails wants it to be called 'spending_thresholds_attributes' for accepts_nested_attributes to work) so I changed it to
<FieldArray
name="spending_thresholds_attributes"
fields={this.props.retailer.spending_thresholds}
component={renderSpendingThresholds}
/>
and data start coming through to the renderSpendingThresholds component in this format
[Object]
0:Object
length:1
__proto__:Array(0)
which React doesn't like for some reason.
Anyone know how to fix this/why those two objects, which hold the same information from the Rails side anyway, are being treated differently?
EDITS
renderSpendingThresholds component
The fields attribute in the renderSpendingThresholds component is the object that's coming through differently depending on how I input it
const renderSpendingThresholds = ({ fields }) => (
<ul className="spending-thresholds">
<li>
<Button size="sm" color="secondary" onClick={(e) => {
fields.push({});
e.preventDefault();
}
}>
Add Spending Threshold
</Button>
</li>
{fields.map((spending_threshold, index) => (
<li key={index}>
<h4>Spending Threshold #{index + 1}</h4>
<Button
size="sm"
color="danger"
title="Remove Spending Threshold"
onClick={() => fields.remove(index)}
>
Remove
</Button>
<Field
name={`${spending_threshold}.spend_amount`}
type="number"
component={renderField}
label="Spend Amount"
placeholder="0"
/>
<Field
name={`${spending_threshold}.bonus_credits`}
type="number"
component={renderField}
label="Bonus Credits"
placeholder="0"
/>
</li>
))}
</ul>
);
It looks like you are passing fields through props and then destructuring the fields out of the props in the callback of the renderSpendingThresholds and discarding the rest. According to the docs, a specific redux-form object is passed through to the render callback. You're essentially overwriting this. Try changing {field} to something like member or spending_threshold. Then you can use the specific map function to iterate over the spending_threshold items. Your field prop should still be available under member.fields or something similar.
For the code that you currently show, who exactly handles the submission?
you use the original flow of form submit?
if so, so please handle that by yourself.
** this line of code, looks weird:
onClick={() => fields.remove(index)}
as you interact directly with the state values...
you need to update the state through
this.setState({fields: FIELDS_WITHOUT_ITEM})
and now when you need to handle your own submission, you don't really care of the input names. Because you are using the state as input.
ie:
class FormSpending extends Component {
handleSubmit() {
var fieldsData = this.state.fields.map(field => {
return {
whateverkey: field.dontcare,
otherKey: field.anotherDontCare
};
});
var formData = {
fields: fieldsData
};
ajaxLibrary.post(URL_HERE, formData).....
}
render() {
return (
...
<form onSubmit={()=>this.handleSubmit()}>
...
</form>
...
);
}
}

How can I make a conditional statement like "include?" method in Ruby on Angular ng-if

Sorry about the difficulty for me to make the title much clearer. I'll explain as much as I can.
I use Rails as the backend (API), and AngularJS as the frontend.
I got several article_ids that have been liked(thumb up) from articleCtrl, named $scope.article_has_liked (it's an array contains several article_ids, like [24,45,55] ), just like below, :
articleCtrl.js.coffee
$http.get(url).success((data)->
console.log(data)
$scope.articles = data.articles
$scope.topic = data.topic
$scope.article_has_liked = data.article_has_liked
)
And I pass these article_ids ($scope.article_has_liked) to the show.html, in order to use "ng-if" to conduct a judgement, just like below:
Show.html
<div ng-if="article_has_liked.include?(article.id)">
<button class="btn btn-link" ng-click="likeItOrNot(article.id, topic.id)">
<span class="glyphicon glyphicon-star"></span>
</button>
</div>
<div ng-if="article_has_liked.exclude?(article.id)">
<button class="btn btn-link" ng-click="likeItOrNot(article.id, topic.id)">
<span class="glyphicon glyphicon-star-empty"></span>
</button>
</div>
Here comes the problem !
I'd like to use .include? method in Ruby to determine if the article.id is included by the article_ids that have been liked. If it is liked, I'll give it a solid star. But I found that the Angular seems not to accept the usage, and it returned the error just like below:
Error: Syntax Error: Token 'undefined' expected : at column NaN of the expression [article_has_liked.include?(article.id)] starting at [article_has_liked.include?(article.id)].
throwError#http://localhost:3000/assets/angular.self-cdfe10db265380c82ec938d307fce2720dc9fb9d8cfa21c78928031af124e282.js?body=1:6672:1
ternary#http://localhost:3000/assets/angular.self-cdfe10db265380c82ec938d307fce2720dc9fb9d8cfa21c78928031af124e282.js?body=1:6827:9
_assignment#http://localhost:3000/assets/angular.self-cdfe10db265380c82ec938d307fce2720dc9fb9d8cfa21c78928031af124e282.js?body=1:6800:16
expression#http://localhost:3000/assets/angular.self-cdfe10db265380c82ec938d307fce2720dc9fb9d8cfa21c78928031af124e282.js?body=1:6796:12
_filterChain#http://localhost:3000/assets/angular.self-cdfe10db265380c82ec938d307fce2720dc9fb9d8cfa21c78928031af124e282.js?body=1:6762:16
statements#http://localhost:3000/assets/angular.self-cdfe10db265380c82ec938d307fce2720dc9fb9d8cfa21c78928031af124e282.js?body=1:6742:25
parser#http://localhost:3000/assets/angular.self-cdfe10db265380c82ec938d307fce2720dc9fb9d8cfa21c78928031af124e282.js?body=1:6661:13
$ParseProvider/this.$get</<#http://localhost:3000/assets/angular.self-cdfe10db265380c82ec938d307fce2720dc9fb9d8cfa21c78928031af124e282.js?body=1:7282:1
compileToFn#http://localhost:3000/assets/angular.self-cdfe10db265380c82ec938d307fce2720dc9fb9d8cfa21c78928031af124e282.js?body=1:9215:16
$RootScopeProvider/this.$get</Scope.prototype.$watch#http://localhost:3000/assets/angular.self-cdfe10db265380c82ec938d307fce2720dc9fb9d8cfa21c78928031af124e282.js?body=1:8547:19
ngIfDirective</<.compile/<#http://localhost:3000/assets/angular.self-cdfe10db265380c82ec938d307fce2720dc9fb9d8cfa21c78928031af124e282.js?body=1:14677:9
nodeLinkFn#http://localhost:3000/assets/angular.self-cdfe10db265380c82ec938d307fce2720dc9fb9d8cfa21c78928031af124e282.js?body=1:4960:13
compositeLinkFn#http://localhost:3000/assets/angular.self-cdfe10db265380c82ec938d307fce2720dc9fb9d8cfa21c78928031af124e282.js?body=1:4539:15
compositeLinkFn#http://localhost:3000/assets/angular.self-cdfe10db265380c82ec938d307fce2720dc9fb9d8cfa21c78928031af124e282.js?body=1:4554:13
compositeLinkFn#http://localhost:3000/assets/angular.self-cdfe10db265380c82ec938d307fce2720dc9fb9d8cfa21c78928031af124e282.js?body=1:4554:13
compositeLinkFn#http://localhost:3000/assets/angular.self-cdfe10db265380c82ec938d307fce2720dc9fb9d8cfa21c78928031af124e282.js?body=1:4554:13
compositeLinkFn#http://localhost:3000/assets/angular.self-cdfe10db265380c82ec938d307fce2720dc9fb9d8cfa21c78928031af124e282.js?body=1:4554:13
compositeLinkFn#http://localhost:3000/assets/angular.self-cdfe10db265380c82ec938d307fce2720dc9fb9d8cfa21c78928031af124e282.js?body=1:4554:13
publicLinkFn#http://localhost:3000/assets/angular.self-cdfe10db265380c82ec938d307fce2720dc9fb9d8cfa21c78928031af124e282.js?body=1:4456:30
ngRepeatAction#http://localhost:3000/assets/angular.self-cdfe10db265380c82ec938d307fce2720dc9fb9d8cfa21c78928031af124e282.js?body=1:15463:15
$watchCollectionAction#http://localhost:3000/assets/angular.self-cdfe10db265380c82ec938d307fce2720dc9fb9d8cfa21c78928031af124e282.js?body=1:8718:11
$RootScopeProvider/this.$get</Scope.prototype.$digest#http://localhost:3000/assets/angular.self-cdfe10db265380c82ec938d307fce2720dc9fb9d8cfa21c78928031af124e282.js?body=1:8812:21
$RootScopeProvider/this.$get</Scope.prototype.$apply#http://localhost:3000/assets/angular.self-cdfe10db265380c82ec938d307fce2720dc9fb9d8cfa21c78928031af124e282.js?body=1:9013:13
done#http://localhost:3000/assets/angular.self-cdfe10db265380c82ec938d307fce2720dc9fb9d8cfa21c78928031af124e282.js?body=1:10266:34
completeRequest#http://localhost:3000/assets/angular.self-cdfe10db265380c82ec938d307fce2720dc9fb9d8cfa21c78928031af124e282.js?body=1:10450:7
createHttpBackend/</xhr.onreadystatechange#http://localhost:3000/assets/angular.self-cdfe10db265380c82ec938d307fce2720dc9fb9d8cfa21c78928031af124e282.js?body=1:10405:1
<!-- ngIf: article_has_liked.include?(article.id) -->
So I want to ask if there is any conditional statement which has similar meaning to .include? that I can use in AngularJS "ng-if", or there is any better way for me to conduct this judgement?
Thanks everyone for helping me this confusing question!
That is a JavaScript relating question, not AngularJS. But may that answer your question:
Often you will need to check whether an array contains a certain item. You can do this by using the indexOf() method. If the code does not find the item in the list, it returns a -1.
var article_has_liked = [24,45,55];
if(article_has_liked.indexOf(99) == -1){
alert("data not found");
}
Not sure but you can try something:
<div ng-if="article_has_liked.indexOf(article.id) != -1">
Note: This above condition is to check for include. If it include your article.id in article_has_liked then only execute that block. If you want to check exclude then you can simply use == instead != I hope it works for you.
ng-if="article_has_liked.include?(article.id)"
update to this one:
ng-if="article_has_liked.include?(article.id):false value here"

JqueryMobile checkbox doesn't like "data-inline"

I'm developing a web app with MVC 3 / Razor and jquery-mobile. In jquery-mobile, normally you can add data_inline = "true" to an object's attributes and it will prevent the element from stretching all the way across the screen, like so:
#Html.DropDownListFor(m => m.value, options, new { data_inline = "true" })
#Html.ActionLink("Text", "Action", null, new {data_role="button", data_inline="true"})
Both of those work fine. But on a checkbox...
#Html.CheckBoxFor(m => m.value, new { data_inline = "true" })
... it doesn't seem to do anything, and I still get a nasty stretched checkbox. Adding data_role="button" doesn't help (not that I expected it to).
Is there any reason why this is so? Any good way I can get my checkbox to not be stretched without resorting to manual CSS modifications?
The jQM Checkbox does not support data-inline. All you need to do is change the label CSS property display to inline-block.
<label class="inline">
<input type="checkbox" name="chk0" class="ui-btn-inline" />Check me
</label>
.inline {
display: inline-block !important;
}

I got jquery-ui sortable working with meteor templates, but is it a bad hack?

I'm trying to use jquery-ui sortable with nested templates in Meteor, as follows. Here are the two templates in question:
<template name="activityEditor">
{{! the main activity editor view }}
<div class="activity-editor">
<input type="text" name="title" class="input-xxlarge" value="{{info.title}}" placeholder="Type a title here...">
<div class="activity-steps">
{{#each info.steps}}
{{>activityStepEditor}}
{{/each}}
</div>
</div>
</template>
<template name="activityStepEditor">
{{! the container view for each step editor }}
<div class="activity-step" data-id="{{_id}}">
<div class="order">{{order}}</div>
{{!....stuff...}}
</div>
</template>
and the template code (using coffeescript):
_.extend Template.activityEditor, {
# ...stuff...
rendered: ->
$(".activity-steps").sortable {
items: '.activity-step'
handle: '.order'
update: ->
stepIds = ($(el).attr('data-id') for el in $('.activity-step'))
$('.activity-steps').empty() #this must be done in order to steps to re-render properly
Lab.Activity.reorderSteps stepIds
}
$(".activity-steps").disableSelection()
}
The only way I can get this code to work and properly rerender the order is by emptying the container of my sortable elements right after they update with $('.activity-steps').empty(). I've tried cancelling the update event and forcing a rerender by changing another variable watched in the context, but any change causes Exception from Meteor.flush(): undefined after which I can't rerender anything until page reload.
This seems to work, and everything rerenders great. So my question is: is there any reason why I shouldn't do this? Is there a better, standard practice way to handle the sortable that I'm not seeing?
In the near future there'll be a better way to do it, as Meteor team is developing its new rendering engine: http://youtube.com/watch?v=ISNEhPG0wnA
(in this video, Avital Oliver shows exactly a way to do it without redrawing the screen: the object in the list is actually moved on all clients)
See this Meteor's Github Wiki entry for more technical info:
http://github.com/meteor/meteor/wiki/New-Template-Engine-Preview
While that's not officially published, if you need it right now, you could try Nazar Leush's approach:
http://github.com/nleush/meteor-todos-sortable-animation
He also published a working example here: http://todos-dnd-animated.meteor.com

jQueryUI dialog - button text not appearing

I have a strange error occurring with the dialog box, I'm loading the dialog box fine, but whenever I assign a button to it, although it'll display the button, it won't display the name of the button. Here is my code that launches the dialog successfully...
jQuery('#'+message_div_id).dialog({
modal: ui_popup_modal
, width: ui_popup_width
, height: ui_popup_height
, resizable: false
, draggable: false
, buttons: {
"Ok": function() {
jQuery( this ).dialog( "close" );
}
}
});
This is the resulting html from bugzilla after the popup has loaded...
< button type="button" text="Ok" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" role="button" aria-disabled="false">< span class="ui-button-text">< /span>< /button>
The span class is the area that should contain the text, but as you can see, it is not. Any ideas?
This inspired me a lot, but it didn't work exactly for me, I made the following modifications. I think this works better.
$('div.ui-dialog-buttonset button.ui-button span.ui-button-text').each(function() {
$(this).html($(this).parent().attr('text'));
});
This works for me with jQuery UI v1.8.22 CDN (tested):
$('div.ui-dialog button.ui-button').each(function() {
$(this).children('.ui-button-text').html($(this).attr('text'));
});
I think there is something missing. It would be nice to see it working. I tried creating a test and I get no text, but the css is missing. If I do this it works:
<button type="button" text="Ok" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" role="button" aria-disabled="false"><span class="ui-button-text">Text Here</span></button>
Sorry, new to SO.
Anyhow, as this piece of code was just part of a bigger piece of functionality and as I couldn't resolve the issue via the example code on the jQueryUI site, I ended up resolving with this :
var button1_text = '';
(ui_popup_but1 != '') ? button1_text = ui_popup_but1 : button1_text = 'OK';
jQuery('button[text="button1"] span').html(button1_text);
I had a similar problem. Finally solved it by upgrading the version of jQuery used from 1.3.2 up to current (1.7.1) at the time. I just noticed that the version of jQuery UI I used is not current (1.8.11 vs current of 1.8.18). I will try downgrading jQuery back and upgrading jQuery UI to current and see what happens.
EDIT: jQuery UI 1.8.18 fixed the issue for me in using both jQuery 1.3.2 and 1.7.1, so it looks like 1.8.11 had a defect that caused it to be not compatible with 1.3.2 (I'm assuming it was supposed to be since .18 is, I would think they wouldn't have changed compatibility between such a small version change).
Had the same issue and ended up patching jquery-ui.js
--- jquery-ui-1.8.23.js 2012-09-14 11:18:34.000000000 +-1000
+++ jquery-ui-1.8.23.js 2012-09-14 11:31:07.000000000 +-1000
## -9088,13 +9088,16 ##
.appendTo(uiButtonSet);
// can't use .attr( props, true ) with jQuery 1.3.2.
$.each( props, function( key, value ) {
if ( key === "click" ) {
return;
}
- if ( key in button ) {
+ if ( key == "text" ) {
+ button.html( value );
+ }
+ else if ( key in button ) {
button[ key ]( value );
} else {
button.attr( key, value );
}
});
if ($.fn.button) {
I had the same problem, but the reason why it was without text was that i had dependency issues. To put it short, i had 2 jquery ui js included in my final html file. When i left only 1 version of jquery ui everything seem to work as expected.

Resources