2016-08-03 12 views
5

Przepraszamy za nieprecyzyjne pytanie. Nie udało się dokładnie zidentyfikować problemu, o którym mowa.Jak utworzyć zadanie z wiadomościami, które wymagają ładunku w wiąz?

Próbuję użyć "wzorca tłumacza" wspomnianego w tym świetnym blogu autorstwa Alexa Lew tutaj: The Translator Pattern: a model for Child-to-Parent Communication in Elm.

Ale bycie w sumie Elm początkujących Nie bardzo rozumiem w następującej sytuacji:

Mam moduł tak (składnik dziecięcej w strukturze):

module Pages.SignUp.Update exposing (update, Msg(..)) 
import Http 
import HttpBuilder exposing (withHeader, withJsonBody, stringReader, jsonReader, send) 
import Task exposing (Task) 
import Json.Decode exposing (Decoder, bool, (:=)) 
import Json.Encode exposing (encode, object, string) 
import String 
import Update.Extra exposing (andThen) 
import Debug 


type alias Model = 
    { displayName : String 
    , displayNameErrors : List (Maybe String) 
    , email : String 
    , emailErrors : List (Maybe String) 
    , password : String 
    , passwordConfirmation : String 
    , passwordErrors : List (Maybe String) 
    , modelValid : Bool 
    , emailValidationPending : Bool 
    , registrationPending : Bool } 


emptyModel : Model 
emptyModel = 
    { displayName = "" 
    , displayNameErrors = [] 
    , email = "" 
    , emailErrors = [] 
    , password = "" 
    , passwordConfirmation = "" 
    , passwordErrors = [] 
    , modelValid = False 
    , emailValidationPending = False 
    , registrationPending = False } 

type InternalMsg 
    = SetEmail String 
    | SetDisplayName String 
    | SetPassword String 
    | SetPasswordConfirm String 
    | Register 
    | RegisterSucceed (HttpBuilder.Response Bool) 
    | RegisterFail (HttpBuilder.Error String) 
    | ValidateModel 
    | Noop 

type OutMsg 
    = UserRegistered 

type Msg 
    = ForSelf InternalMsg 
    | ForParent OutMsg 

type alias TranslationDictionary msg = 
    { onInternalMessage: InternalMsg -> msg 
    , onUserRegistered: msg 
    } 

type alias Translator msg = 
    Msg -> msg 


translator : TranslationDictionary msg -> Translator msg 
translator { onInternalMessage, onUserRegistered } msg = 
    case msg of 
     ForSelf internal -> 
      onInternalMessage internal 
     ForParent UserRegistered -> 
      onUserRegistered 

never : Never -> a 
never n = 
    never n 

generateParentMessage : OutMsg -> Cmd Msg 
generateParentMessage outMsg = 
    Task.perform never ForParent (Task.succeed outMsg) 

init : (Model, List Notification) 
init = 
    (emptyModel, []) 

update : InternalMsg -> Model -> (Model, Cmd Msg) 

update msg model = 
    case Debug.log "Signup action" msg of 
     SetEmail emailStr -> 
      let model' = 
       {model | email = emailStr } 
      in 
       update ValidateModel model' 

     SetDisplayName nameStr -> 
      let model' = 
       { model | displayName = nameStr } 
      in 
       update ValidateModel model' 

     SetPassword passwordStr -> 
      let model' = 
       { model | password = passwordStr } 
      in 
       update ValidateModel model' 

     SetPasswordConfirm passwordConfirmStr -> 
     let model' = 
      { model | passwordConfirmation = passwordConfirmStr } 
     in 
      update ValidateModel model' 

     ValidateModel -> 
      let validatedModel = 
        validateModel model 
       test = Debug.log "validated model" validatedModel 
      in 
       (validatedModel, Cmd.none) 

     Register -> 
      ({ model | registrationPending = True }, registerUser model) 

     RegisterSucceed _ -> 
      ({ model | registrationPending = False }, (generateParentMessage UserRegistered)) 

     RegisterFail error -> 
      case error of 
       HttpBuilder.BadResponse response -> 
        case Debug.log "Register response status" response.status of 
         422 -> 
          ({ model | registrationPending = False }, Cmd.none) 
         _ -> 
          ({ model | registrationPending = False }, Cmd.none) 
       _ -> 
        ({ model | registrationPending = False }, Cmd.none) 
     Noop -> 
      (model, Cmd.none) 


registerUser : Model -> Cmd Msg 
registerUser model = 
    let url = 
      "/api/users" 

     user = 
      object [ 
       ("user", 
        object 
        [ 
         ("display_name", (string model.displayName)), 
         ("email", (string model.email)), 
         ("password", (string model.password)), 
         ("passwordConfirmation", (string model.passwordConfirmation)) 
        ] 
       ) 
      ] 

     postRequest = 
      HttpBuilder.post url 
      |> withHeader "Content-type" "application/json" 
      |> withJsonBody user 
      |> send (jsonReader decodeRegisterResponse) stringReader 
    in 
     Task.perform ForSelf RegisterFail ForSelf RegisterSucceed postRequest 

decodeRegisterResponse : Decoder Bool 
decodeRegisterResponse = 
     "ok" := bool 

validateRequired : String -> String -> Maybe String 

validateRequired fieldContent fieldName = 
      case String.isEmpty fieldContent of 
       True -> Just <| String.join " " [ fieldName, "required" ] 
       False -> Nothing 

validateEmail : String -> List (Maybe String) 

validateEmail email = 
    let requiredResult = 
      validateRequired email "Email" 
    in 
     [requiredResult] 

validatePassword : String -> String -> List (Maybe String) 
validatePassword password passwordConf = 
    let requiredResult = 
      validateRequired password "Password" 
     confirmResult = 
      case password == passwordConf of 
       True -> Nothing 
       False -> Just "Password confirmation does not match" 
    in 
     [ requiredResult, confirmResult ] 

validateModel : Model -> Model 
validateModel model = 
    let emailResult = 
      validateEmail model.email 
     displayNameResult = 
      validateRequired model.displayName "Displayname" :: [] 
     passwordResult = 
      validatePassword model.password model.passwordConfirmation 
     errors = 
      List.concat [emailResult, displayNameResult, passwordResult ] |> List.filterMap identity 
     modelValid = List.isEmpty errors 
    in 
     { model | 
      emailErrors = emailResult, 
      displayNameErrors = displayNameResult, 
      passwordErrors = passwordResult, 
      modelValid = modelValid 
     } 

Problem polega funkcja registerUser, która oczywiście nie działa tak, jak jest teraz. Nie mogę go odzyskać Cmd Msg. Mogę zrobić tak, aby zwrócić Cmd InternalMsg, ale potem oczywiście napotkasz problemy w funkcjach aktualizacji Zarejestruj wiadomość. Tam musiałbym przekonwertować Cmd InternalMsg na Cmd Msg.

Próbowałem rozwiązać ten problem w obu miejscach, ale zawsze mam problem. Najprawdopodobniej jest to proste rozwiązanie, ale niestety nie ma na to żadnych umiejętności, jak się wydaje.

Każda pomoc będzie mile widziana.

+1

Jest to zgadnij, ale czy próbowałeś ['Cmd.map ForSelf: Cmd InternalMsg -> Cmd Msg'] (http://package.elm-lang.org/packages/elm-lang/core/4.0.0/Platform-Cmd# mapa)? – Lynn

Odpowiedz

7

To jest brzydka część Translator wzór, należy Cmd.map polecenia do Msg orędzia, więc zamiast:

Task.perform ForSelf RegisterFail ForSelf RegisterSucceed postRequest 

Powinieneś mieć coś takiego:

Cmd.map ForSelf (Task.perform RegisterFail RegisterSucceed postRequest) 
+0

Jeśli nie lubisz używać 'Cmd.map' tutaj, dlaczego nie robić' Task.perform (ForSelf << RegisterFail) (ForSelf << RegisterSucceed) postRequest' zamiast tego? –

+0

@ Operatorzy składu funkcji Zimmi48 są mylące dla osób nowych w Wiązach i FP, nie polecałbym ich używania. Brzydka część to ten dodatkowy poziom złożoności, a nie "Cmd.map". – halfzebra

+0

Nie zgadzam się. Skład funkcji jest pojęciem, o którym wie każda osoba, która opanowała matematykę szkolną. Zaletą używania go w tym przypadku jest to, że wskazuje on gdzie był błąd (podając 5 argumentów dla 'Task.perform' zamiast tylko trzech). –

Powiązane problemy