2016-08-05 3 views
2

私はエルムの新人です。私はこれまでのところ本当に好きですが、私は私の頭を包み込むことができないという問題にぶつかってきました。Transform Html DOM

私は[1-6]要素の各時間内のリンクを追加しますので、(それをシンプルに保つこと)のようなものにそれを変換したい

div [] 
    [ h1 [] [text "Headline 1"] 
    , p [] [text "Some text"] 
    , h2 [] [text "Headline 2"] 
    ] 

例えば私は、HTML DOMを持っている

div [] 
    [ h1 [] [ text "Headline 1" 
      , [a [name "headline"] [text "#"] 
      ] 
    , p [] [text "Some text"] 
    , h2 [] [text "Headline 2" 
      , [a [name "headline"] [text "#"] 
      ] 
    ] 

これは概念的にはあまり難しくありません。要素がh [1-6]の場合、DOMを見て、a-linkを子要素として追加します。しかし、エルムの私の理解はそれを働かせるほど十分ではありません。

これまで私がこれまで試みてきたことは次のとおりです。

transform : Html a -> Html a 
transform node = 
    -- check if the tag is h1-h6 
    case node.tag of 
     -- add a-link to h1 children 
     "h1" -> { node | children = (a [name "headline"] [text "#") :: node.children } 
     "h2" -> { node | children = (a [name "headline"] [text "#") :: node.children } 
     -- do this for all nodes in the tree 
     _ -> { node | children = List.map transform node.children } 

これは機能しません。

The type annotation for `transform` does not match its definition. 

40| transform : Html a -> Html a 
       ^^^^^^^^^^^^^^^^ 
The type annotation is saying: 

    VirtualDom.Node a -> VirtualDom.Node a 

But I am inferring that the definition has this type: 

    { b | tag : String, children : List (Html a) } 
    -> { b | children : List (Html a), tag : String } 

私は、ジェネリック型aは、そのフィールドを持っていない可能性がありますので、私はnode.tagを行うことができないことを理解しています。タイプセーフではありません。たとえば、テキストノードにタグフィールドはありませんが、まだHtml.Html aのインスタンスです。

> text "Hello World" 
{ type = "text", text = "Hello World" } : Html.Html a 

私の質問は、どうすればいいですか?これはできますか?私はこれをしてはいけませんか?

答えて

2

Html msgタイプの既存の値を変更することはできません。

これらは最終的な内部構造であり、実際のHTMLノードにはプログラムの出力としてVirtual DOMが表示されます。

Html msgVirtualDom.Node a

あなたがレコードとしてそれらを使用しようとしているの別名であるが、それは単なるJavaScriptオブジェクトです。

エルムREPLがここに抽象データ構造の文字列表現を出力します

> text "Hello World" 
{ type = "text", text = "Hello World" } : Html.Html a -- not a record 

代わりHtml msg -> Html msgを変換しようとすると、あなたのような何かを試してみてください:

エルムで
-- Input example: [ "#", "http://google.com/", "http://package.elm-lang.org/" ] 

linksView : List String -> Html msg 
linksView links = 
    links 
     |> List.map (\link -> a [ href link ] [ text link ]) 
     |> div [] -- Expected output: <div> with thre links 
+0

を私は出力がjavascriptのあったことを疑いました。私の "Html msg"は 'Markdown 'の出力に由来します。toHtml'から 'Html msg'として返される前に、それを操作する良い方法はありません。出力を変換することができないほど悪いです。 –

1

を、Html aが本当にあります出力としてのみ役立ちます。 transform機能の試行中に入力として使用することは決してありません。

ドメインを記述するモデルを作成し、それをview関数に渡してhtmlをレンダリングすると、より効果的です。

type alias Article = 
    { priority : Priority 
    , headline : String 
    , body : String 
    } 

type alias Model = 
    List Article 

type Priority = First | Second 

あなたのビューは、このようなものになります:

view : Model -> Html msg 
view = 
    div [] << List.map viewArticle 

viewArticle : Article -> Html msg 
viewArticle article = 
    let 
    priorityTag = 
     case article.priority of 
     First -> h1 
     Second -> h2 
    in 
    div [] 
     [ priorityTag [] 
     [ text article.headline 
     , a [ name "headline" ] [ text "#" ] 
     ] 
     , p [] [ text article.body ] 
     ] 
+0

私はハーフゼブラにコメントしたので、Markdown.toHtmlを使って 'Html msg'に変換するマークダウンの内容を持っています。私は自分のマークダウンの内容にリンクを望んでおらず、明らかに 'Markdown.toHtml'の出力を変換してリンクを追加することはできません。それは残念です。 –

+0

Gotcha。 Markdownライブラリを拡張することをお勧めしましたが、それはJavaScriptライブラリの周りのラッパーにすぎません。https://github.com/chjj/marked –

+0

@Mikael Lundin Markdown.toHtmlに渡す前にMarkdownをプログラムで増やすことはできますか? –