2016-12-15 33 views
12

Pracuję z istniejącą aplikacją Rails, w której nawigacja musi być kontynuowana na zapleczu (ze względu na złożoność i ograniczenia czasowe). Celem jest uzyskanie niektórych stron wygenerowanych za pomocą Wiązu, a niektórych za pomocą Railsów, bez skrótów i bez przeładowania całej strony (przynajmniej na stronach Wiązów). Uproszczona wersja nawigacji wygląda następująco:Czy można prowadzić aplikację Elm z istniejącą nawigacją zbudowaną poza aplikacją Elm?

<nav> 
    <a href="rails-page-1">... 
    <a href="rails-page-2">... 
    <a href="elm-page-1">... 
    <a href="elm-page-2">... 
</nav> 

<div id="elm-container"></div> 

Mam eksperymentował z pakietem nawigacyjnym Elm, a elm-route-url, ewentualnie zbliżając się z nim chyba jestem fundamentalnie niezrozumienia możliwości tego pakietu.

Czy istnieje sposób, aby to osiągnąć? Zrobiłem to działając przy użyciu tagów hash, ale bez nich nie ma szczęścia.

+0

myślę, że byłoby to możliwe, aby dołączyć detektory zdarzeń do linki kotwiczne do preventDefault i przekazać intencję przez port do Elm –

+0

@SimonH Wygląda na to, i myślę o tej opcji. Chciałbym zobaczyć, jak pozostać w Elm, jeśli to możliwe. – scoots

Odpowiedz

7

wykorzystujące znaczniki hash

Cóż masz chichot ze mnie.

Mam tego gościa w moim pliku Helpers.elm, którego mogę użyć zamiast Html.Events.click.

{-| Useful for overriding the default `<a>` behavior which 
    causes a refresh, but can be used anywhere 
-} 
overrideClick : a -> Attribute a 
overrideClick = 
    Decode.succeed 
     >> onWithOptions "click" 
      { stopPropagation = False 
      , preventDefault = True 
      } 

Więc na a [ overrideClick (NavigateTo "/route"), href "/route" ] [ text "link" ] co pozwoliłoby średnim kliknięcie elementu jak również przy użyciu stan Push zaktualizować nawigację.

To, czego potrzebujesz, to coś podobnego w JavaScript, które działa z pushState, a nie chcesz zrujnować wrażenia z kliknięcia środkowym przyciskiem myszy. Możesz przejąć wszystkie zdarzenia związane z jego zdarzeniem, aby zatrzymać przeglądarkę i wprowadzić nowy stan za pośrednictwem href celu. Możesz przekazać nawigację do <a> s w procedurze obsługi zdarzeń. Ponieważ środowisko wykonawcze Navigation nie obsługuje zewnętrznego odsłuchiwania historii (wydaje się, że używa on menedżera efektów), musisz przesłać wartość przez port - na szczęście, jeśli używasz pakietu Navigation, powinieneś już mają części.

Na końcu wiązu użyj UrlParser.parsePath w połączeniu z jednym z Navigation programs. Utwórz port do subskrybowania za pomocą tego samego komunikatu, który jest używany do wewnętrznych zmian adresu URL.

import Navigation exposing (Location) 


port externalPush : (Location -> msg) -> Sub msg 


type Msg 
    = UrlChange Location 
    | ... 


main = 
    Navigation.program UrlChange 
     { ... 
     , subscriptions : \_ -> externalPush UrlChange 
     } 

Po załadowaniu strony, użyj tego:

const hijackNavClick = (event) => { 
    // polyfill `matches` if needed 
    if (event.target.matches("a[href]")) { 
    // prevent the browser navigation 
    event.preventDefault() 
    // push the new url 
    window.history.pushState({}, "", event.target.href) 
    // send the new location into the Elm runtime via port 
    // assuming `app` is the name of `Elm.Main.embed` or 
    // whatever 
    app.ports.externalPush.send(window.location) 
    } 
} 


// your nav selector here 
const nav = document.querySelector("nav") 


nav.addEventListener("click", hijackNavClick, false) 
+0

Dzięki, wziąłem Twoje sugestie. Korzystając z tego rozwiązania, konieczne jest użycie flag lub portów, aby uzyskać pełną funkcjonalność? Jeśli nie, czy możesz wyjaśnić, co dzieje się na końcu Wiązu? Jak na razie moja aktualizacja nie jest uruchamiana. – scoots

+0

Arg ... Tak, zagłębiłem się w natywny kod (https://github.com/elm-lang/navigation/blob/2.0.1/src/Native/Navigation.js) i wygląda na to, że go nie słucha zmienić wydarzenia. Zaktualizowałem główną odpowiedź za pomocą rozwiązania portu. – toastal