action has wrong type in ReasonReact reducer - reason

I'm trying to create a simple todo app, this is an input component and I need a reducer to update the state of the input. This code is throwing the error - This pattern matches values of type action but a pattern was expected which matches values of type unit => string
For some reason it expects action to be unit => string and I have no idea why. Can anyone help?
type state = string;
type action =
| InputChange(string);
let component = ReasonReact.reducerComponent("Input");
let make = (~onSubmit, _children) => {
...component,
initialState: () => "",
reducer: action =>
switch (action) {
| InputChange(text) => ReasonReact.Update(text)
},
render: ({state: todo, send}) =>
<input
className="input"
value=todo
type_="text"
placeholder="What do you want todo"
onChange={e => send(ReactEvent.Form.target(e)##value)}
onKeyDown={
e =>
if (ReactEvent.Keyboard.key(e) == "Enter") {
onSubmit(todo);
send(() => "");
}
}
/>,
};

The type of action is inferred by the use of send in render, where you pass it () => "", a function of type unit => string. It should be send(InputChange("")).
You're also missing the state argument on reducer. It should be reducer: (action, state) => ..., or reducer: (action, _state) => ... to avoid the unused warning, since you're not using it.

Related

How to pass onClick handler from parent to child components through optional labeled arguments

I want to pass an event handler down a series of components from parent to child. Here is a working example:
Index.re
ReactDOMRe.renderToElementWithId(
<App myHandler={_evt => Js.log("my handler clicked")} />,
"root",
);
App.re
let component = ReasonReact.statelessComponent(__MODULE__);
let make = (~myHandler, _children) => {
...component,
render: _self => <MyComponent myHandler />,
};
MyComponent.re
let component = ReasonReact.statelessComponent(__MODULE__);
let make = (~myHandler, _children) => {
...component,
render: _self =>
<div onClick=myHandler> {ReasonReact.string("click me")} </div>,
}
As this code is now, the myHandler argument is required at each component usage otherwise we get error:
This call is missing an argument of type (~myHandler: ReactEvent.Mouse.t => unit)
Labeled arguments can be made optional by adding a =? in the function declaration like so:
let component = ReasonReact.statelessComponent(__MODULE__);
let make = (~myHandler=?, _children) => {
...component,
render: _self =>
<div onClick=myHandler> {ReasonReact.string("click me")} </div>,
};
However this gives a compilation error:
5 │ ...component,
6 │ render: _self =>
7 │ <div onClick=myHandler> {ReasonReact.string("click me")} </div>,
8 │ };
This has type:
option('a)
But somewhere wanted:
ReactEvent.Mouse.t => unit
I thought that perhaps the compiler might need a hint. So then I tried explicitly adding that type to the function declaration like this:
let component = ReasonReact.statelessComponent(__MODULE__);
let make = (~myHandler: ReactEvent.Mouse.t => unit=?, _children) => {
...component,
render: _self =>
<div onClick=myHandler> {ReasonReact.string("click me")} </div>,
};
But then the error flips on me and gives me:
4 │ let make = (~myHandler: ReactEvent.Mouse.t => unit=?, _children) => {
5 │ ...component,
6 │ render: _self =>
This pattern matches values of type
ReactEvent.Mouse.t => unit
but a pattern was expected which matches values of type
option('a)
And now I'm all confused.
Just to provide a proper answer, since it seems unlikely that this will get closed as a duplicate
Optional arguments are turned into options on the callee's side of things. Otherwise, how would you represent the absence of the argument. There are no nulls, remember, so nullability must be expressed explicitly.
myHandler is therefore an option(ReactEvent.Mouse.t => unit). onClick is of course also an optional argument which will be turned into an option, but since this is, normally, done automatically we can't just feed it an option directly.
Fortunately, someone already thought of this scenario and added a syntactic construct to be able to pass options explicitly as optional arguments. Just add a ? before the expression passed to the argument, and you should be good:
<div onClick=?myHandler> {ReasonReact.string("click me")} </div>,
So for the optional argument to work you have to handle the optional case itself in the MyComponent component.
let component = ReasonReact.statelessComponent(__MODULE__);
let make = (~myHandler=?, _children) => {
...component,
render: _self => {
let myHandler = switch myHandler {
| None => (_e) => Js.log("default");
| Some(handler) => handler;
};
<div onClick=myHandler> {ReasonReact.string("click me")} </div>
}

In AutoMapper 8.0 missing ResolveUsing

Prior to AutoMapper 8.0, I have used this code:
CreateMap<ApplicationRole, RoleViewModel>()
.ForMember(d => d.Permissions, map => map.MapFrom(s => s.Claims))
.ForMember(d => d.UsersCount, map => map.ResolveUsing(s => s.Users?.Count ?? 0))
.ReverseMap();
The documentation says that you have to change ResolveUsing for MapFrom, but I have a Error "No propagation Null"
.ForMember(d => d.UsersCount, map => map.MapFrom(s => s.Users?.Count ?? 0))
How I have to resolve it?
Replace ResolveUsing with MapFrom, and add one more input parameter to the lambda (TDestination).
.ForMember(d => d.UsersCount, map => map.MapFrom((s,d) => s.Users?.Count ?? 0))
EDIT November 2022
Newest version(s) of AutoMapper doesn't support lambda expression in MapFrom. In this case you have to extract it to a method (Func) or do it inline if you can.
Also, null propagation isn't allowed unless it's a method.
.ForMember(d => d.UsersCount, map => map.MapFrom(s => MapUserCount(s))
--------------
private static int MapUserCount(ApplicationRole src) {
return src.Users?.Count ?? 0;
}
or
.ForMember(d => d.UsersCount, map => map.MapFrom(s => s.Users == null ? 0 : s.Users.Count))
In AutoMapper 8.0 missing ResolveUsing
I also have the same issue and I'm using the following prototype of ResolveUsing:
void ResolveUsing(Func<TSource, TResult> mappingFunction);
Instead of replacing existing code, I preferred to create an extension method:
using System;
using AutoMapper;
namespace myLibrary.Extensions
{
public static class AutoMapperCompatibilityExtensions
{
// Summary:
// Resolve destination member using a custom value resolver callback. Used instead
// of MapFrom when not simply redirecting a source member This method cannot be
// used in conjunction with LINQ query projection
//
// Parameters:
// resolver:
// Callback function to resolve against source type
public static void ResolveUsing<TSource, TDestination, TMember, TResult>(this IMemberConfigurationExpression<TSource, TDestination, TMember> member, Func<TSource, TResult> resolver) => member.MapFrom((Func<TSource, TDestination, TResult>)((src, dest) => resolver(src)));
}
}
Later, in my code, I simply referred the namespace:
using myLibrary.Extensions;
...
... map.ResolveUsing(s => ...
...
Hope this helps.
You don't need to use this expression, you can "Users.Count" and it'll return 0 if the list is empty.

How do I override compare_fields when using Rose::HTML::Form

So I'm trying use Rose::HTML::Form and I want my fields to appear based on 'rank' rather than by name (the default) .
I've written a comparator subroutine:
sub _order_by_rank {
my ($self, $one, $two) = #_;
return $one->rank <=> $two->rank;
};
and referenced it in my form constructor:
Rose::HTML::Form->new(method => 'post', compare_fields => \&_order_by_rank);
But I am then left with:
Can't call method "name" on unblessed reference at /usr/lib/perl5/site_perl/5.8.8/Rose/HTML/Form/Field/Collection.pm line 405.
It seems to call the comparator before I've added anything.
After constructing the form object, I add some fields and then call init_fields:
$form->add_fields(
id => { type => 'hidden', value => "", rank => 0 },
number => { type => 'int', size => 4, required => 1, label => 'Plant Number', rank => 1 },
name => { type => 'text', size => 25, required => 1, label => 'Plant Name', rank => 2 },
...
);
$form->init_fields;
According to the documentation this is something people usually do. What it doesn't explain is how to do it.
Hopefully someone can explain this to me before I have to buy a new keyboard :)
From the documentation it looks as though, rather than passing in a subroutine reference, you need to subclass Rose::HTML::Form and override the compare_fields method.
The default comparison method is Rose::HTML::Form::compare_fields. You have to create subclasses if you want different sorting methods for different forms.
It would help me to explain further if you showed your full code.

How to disable unavailable dates in the CJuiDatePicker widget

I am building a scheduling app. I am able to sort the database using the CJuiDatePicker widget's "onSelect" option. Now I am trying to use the "beforeShow" option to ensure that only dates that have tasks can be selectable. Can anyone help?
$this->widget('zii.widgets.jui.CJuiDatePicker', array(
'model'=>$dataProvider,
'attribute'=>'start_time',
'options'=>array(
'dateFormat' => 'yy-mm-dd',
'changeMonth' => true,
'changeYear' => true,
'beforeShowDay' => 'js:$.datepicker.noWeekends',
'beforeShow' => "js:function Check_Alert2(){
Check_Alert();
}
",
'onSelect' => "js:function SearchFunc() {
var data = $('input').serialize();
var url = document.URL;
var params = $.param(data);
url = url.substr(0, url.indexOf('?'));
window.History.pushState(null, document.title,$.param.querystring(url, data));
}"
),
'htmlOptions'=>array(
'style'=>'height:20px;',
'readonly' =>true,
),
));
i am still using the original code. I need an array generated within the beforeshowday. When i run your code it fails on the getdates() function call.
'beforeShowDay' => 'js:function(date){
var array = ["2013-10-30","2013-10-31","2013-12-18","2013-12-25"];
var string = jQuery.datepicker.formatDate("yy-mm-dd", date);
if (array.indexOf(string) == -1){
return [false,"", "No event"];
} else return [true,"", "Event"];

OR operator in Mongo 'update' $criteria

I want to check for an existing record by matching either title or url fields. If either one matches, update that record. Otherwise, insert.
How do write the following properly (using Mongoid in Ruby):
articles.update(
{ **:title => story.title OR :url => story.url** },
{ :title => story.title, :url => story.url, :source => story.source, :last_updated => Time.now },
{ :upsert => true } )
Thanks!
You need do the request and update it like :
'''
articles.any_of({:title => xxx}, {:url => yyyy}).update( :foo => 'bar')
'''