Вопрос

New to Yesod, Javascript and web programming in general, I don't really know where to start looking. Here's the thing: I wrote a little custom form field in Yesod that shows two multi select lists side by side, and the user can shuffle items from one list to the other ("pick items"). The result of the field is the list of items on the right when the user presses submit.

This works nicely in general, except when it doesn't :-): Every now and then the browser hangs on submit (POST) for like 30 seconds, and then reports a 500 internal server error, complaining about missing encoding. No POST was received by the web server in this case. If I do not wait these 30 seconds, but instead stop and retry (Firefox) or just retry (Chrome), it works. Is there something obvious I am missing here?

Here's the Form Code:

import Import
import Data.Text as T

toFromField :: [(Text, Int)] -> Field Handler [(Int)] 
toFromField sis = 
    Field
    { fieldParse = \rawVals _ ->
        case rawVals of
            [] -> return $ Right Nothing
            [xs] -> return $ Right $ Just $ Import.map parseInt $ Import.filter ("" /=) $ splitOn "_" xs 
    , fieldView = \idAttr nameAttr otherAttrs eResult isReq -> 
           $(widgetFile "tofrom")
    , fieldEnctype = Multipart --UrlEncoded
    }

mkOptions :: [(Text, Int)] -> WidgetT a IO ()
mkOptions sis = do
  mapM_ (\(x, i) -> opt x i) sis

opt :: Text -> Int -> WidgetT a IO ()
opt s i = [whamlet|   
             <option value="#{i}">#{s}
        |]     

parseInt :: Text -> Int 
parseInt t = 
  let [(x,_)] = reads (T.unpack t) :: [(Int, String)]
  in x    

and here's the Julius:

function sortSelect(selElem) {
        var tmpAry = new Array();
        for (var i=0;i<selElem.options.length;i++) {
            tmpAry[i] = new Array();
            tmpAry[i][0] = selElem.options[i].text;
            tmpAry[i][1] = selElem.options[i].value;
        }
        tmpAry.sort();
        while (selElem.options.length > 0) {
            selElem.options[0] = null;
        }
        for (var i=0;i<tmpAry.length;i++) {
            var op = new Option(tmpAry[i][0], tmpAry[i][1]);
            selElem.options[i] = op;
        }
        return;
}
function move(fromID, toID, storeID, dir) 
{
  var from = document.getElementById(fromID);
  var to = document.getElementById(toID);
  for (var i = 0; i < from.options.length; i++)
    {
        if (from.options[i].selected)
        {                   
            to.options.add(new Option(from.options[i].text, from.options[i].value));
            from.remove(i--);
        }
    }
  var storeValue = "";
  var rightside = "";
  if (dir == 'left') { rightside=from; } else { rightside=to };
  for (var i = 0; i < rightside.options.length; i++)
    {
            storeValue = storeValue + rightside.options[i].value + '_';
    }
  document.getElementById(storeID).value = storeValue;
  sortSelect(to);
}

Hamlet:

  <table>
    <tr>
      <td rowspan="2"><select id=#{idAttr}-from  name=#{nameAttr}-from multiple> ^{mkOptions sis}
      <td><input type=button name="To" value=">>>" 
                 onclick="move('#{idAttr}-from','#{idAttr}-to','#{idAttr}', 'right')">
      <td rowspan="2"><select id=#{idAttr}-to name=#{nameAttr}-to multiple>
    <tr>
      <td><input type=button name="From" value="<<<" 
                 onclick="move('#{idAttr}-to','#{idAttr}-from','#{idAttr}', 'left')">
  <input type="hidden" id=#{idAttr} name=#{nameAttr}> 

and the part of the Handler file:

generateSel label recTime route = do
    recs <- getRecs recTime    

    (widget, enctype) <- generateFormPost $ renderDivs 
        $ aopt (toFromField recs) label Nothing
    defaultLayout
        [whamlet|
           <form method=post action=@{route} enctype=#{enctype}>
                ^{widget}
                <input type=submit value="Los">
        |]
Это было полезно?

Решение

Problem had nothing to do with form, as Michael suggested. settings.yml had wrong entry. Wrong entry in settings.yml.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top