Kuinka monta kertaa olet yrittänyt selvittää web-käyttöliittymääsi ja löytänyt itsesi sotkeutuneena monimutkaisten tapahtumaketjujen käsittelevään koodiin?
Yrititkö koskaan muokata koodia käyttöliittymälle, joka käsittelee paljon komponentteja, jotka on rakennettu jQueryllä, Backbone.js: llä tai muilla suosituilla JavaScript-kehyksillä?
Yksi tuskallisimmista asioista näissä skenaarioissa on yrittää seurata useita määrittelemättömiä tapahtumasarjoja sekä ennakoida ja korjata kaikki nämä käyttäytymismallit. Yksinkertaisesti painajainen!
Olen aina etsinyt tapoja välttää tämä helvetillinen osa web-käyttöliittymäkehitystä. Backbone.js toimi minulle hyvin tässä suhteessa antamalla web-käyttöliittymille rakenteen, josta he ovat puuttuneet pitkään. Mutta kun otetaan huomioon se, että se tarvitsee tehdä mitättömimpiä asioita, se ei osoittautunut paljon paremmaksi.
Sitten tapasin Jalava .
Elm on staattisesti kirjoitettu toiminnallinen kieli, joka perustuu Haskell-ohjelmointikieleen, mutta a yksinkertaisempi erittely . Kääntäjä (myös rakennettu Haskellin avulla) jäsentää Elm-koodin ja kääntää sen JavaScriptiksi.
Elm rakennettiin alun perin käyttöliittymän kehittämistä varten, mutta ohjelmistosuunnittelijat ovat löytäneet tapoja käyttää sitä myös palvelinpuolen ohjelmointiin.
Tässä artikkelissa on yleiskatsaus siitä, kuinka Elm voi muuttaa tapaa, jolla ajattelemme web-käyttöliittymän kehitystä, sekä johdanto tämän toiminnallisen ohjelmointikielen perusteisiin. Tässä opetusohjelmassa kehitämme yksinkertaisen ostoskorin kaltaisen sovelluksen Elm-sovelluksen avulla.
Elm lupaa monia etuja, joista suurin osa on erittäin hyödyllisiä puhtaan web-käyttöliittymän arkkitehtuurin saavuttamiseksi. Elm tarjoaa paremmat HTML-renderoinnin suorituskyvyn edut muiden suosittujen kehysten (jopa React.js) yli. Lisäksi Elm sallii kehittäjien kirjoittaa koodia, joka käytännössä ei tuota suurinta osaa ajonaikaisia poikkeuksia, jotka vaivaavat dynaamisesti kirjoitettuja kieliä, kuten JavaScriptiä.
Kääntäjä päättelee tyypit automaattisesti ja antaa ystävällisiä virheitä, mikä saa kehittäjän tietämään mahdolliset ongelmat ennen ajonaikaa.
NoRedInkillä on 36 000 Elm-riviä, ja yli vuoden tuotannon jälkeen se ei ole vieläkään tuottanut yhtä ajonaikaista poikkeusta. [ Lähde ]
Sinun ei tarvitse muuntaa koko olemassa olevaa JavaScript-sovellustasi vain, jotta voit kokeilla Elmia. Erinomaisen JavaScript-yhteentoimivuutensa avulla voit jopa ottaa vain pienen osan olemassa olevasta sovelluksestasi ja kirjoittaa sen uudelleen Elmiin.
Elmillä on myös erinomainen dokumentointi joka paitsi antaa sinulle perusteellisen kuvauksen sen tarjonnasta, mutta antaa myös oikean oppaan web-käyttöliittymän rakentamiseen Elm-arkkitehtuuri - jotain, joka sopii mainiosti modulaarisuuteen, koodin uudelleenkäyttöön ja testaukseen.
Aloitetaan hyvin lyhyellä katkelmalla Elm-koodista:
import List exposing (..) cart = [] item product quantity = { product = product, qty = quantity } product name price = { name = name, price = price } add cart product = if isEmpty (filter (item -> item.product == product) cart) then append cart [item product 1] else cart subtotal cart = -- we want to calculate cart subtotal sum (map (item -> item.product.price * toFloat item.qty) cart)
Mikä tahansa teksti, jota edeltää
--
on kommentti Elm .
Tässä määritellään ostoskori tavaraluettelona, jossa jokainen tuote on tietue, jolla on kaksi arvoa (tuote, jota se vastaa, ja määrä). Jokainen tuote on levy, jolla on nimi ja hinta.
Tuotteen lisääminen ostoskoriin edellyttää tarkistamista, onko tuote jo ostoskorissa.
Jos se tapahtuu, emme tee mitään; muuten lisäämme tuotteen ostoskoriin uutena tuotteena. Tarkistamme, onko tuote jo ostoskorissa suodattamalla luettelo, sovittamalla jokainen tuote tuotteeseen ja tarkistamalla, onko tuloksena oleva suodatettu luettelo tyhjä.
Välisumman laskemiseksi toistetaan ostoskorin kohteet, löydetään vastaava tuotemäärä ja hinta ja summataan kaikki yhteen.
Tämä on yhtä minimalistista kuin kärry ja siihen liittyvät toiminnot voivat saada. Aloitamme tästä koodista ja parannamme sitä askel askeleelta tekemällä siitä kokonaisen verkkokomponentin tai ohjelman Elmin termein.
Aloitetaan lisäämällä tyypit ohjelmasi eri tunnisteisiin. Hirvi kykenee päättelemään tyypit itse, mutta hyödyntämään Elmistä ja sen kääntäjistä on suositeltavaa, että tyypit ilmoitetaan nimenomaisesti.
module Cart1 exposing ( Cart, Item, Product , add, subtotal , itemSubtotal ) -- This is module and its API definition We build an easy shopping cart. @docs Cart, Item, Product, add, subtotal, itemSubtotal - import List exposing (..) -- we need list manipulation functions Cart is a list of items. - type alias Cart = List Item - type alias Item = { product : Product, qty : Int } Product is a record with name and price - type alias Product = { name : String, price : Float } We want to add stuff to a cart. This is a function definition, it takes a cart, a product to add and returns new cart - add : Cart -> Product -> Cart This is an implementation of the 'add' function. Just append product item to the cart if there is no such product in the cart listed. Do nothing if the product exists. - add cart product = if isEmpty (filter (item -> item.product == product) cart) then append cart [Item product 1] else cart I need to calculate cart subtotal. The function takes a cart and returns float. - subtotal : Cart -> Float - subtotal cart = sum (map itemSubtotal cart) Item subtotal takes item and return the subtotal float. - itemSubtotal : Item -> Float Subtotal is based on product's price and quantity. - itemSubtotal item = item.product.price * toFloat item.qty
Tyyppimerkinnöillä kääntäjä voi nyt tarttua ongelmiin, jotka muuten olisivat johtaneet ajonaikaisiin poikkeuksiin.
Elm ei kuitenkaan pysähdy siihen. Hirmuarkkitehtuuri opastaa kehittäjiä yksinkertaisen mallin avulla web-käyttöliittymien jäsentämiseen, ja se tapahtuu käsitteiden kautta, jotka useimmat kehittäjät ovat jo tunteneet:
Jos ajattelet koodisi osaa, joka käsittelee päivitykset ohjaimena sinulla on jotain hyvin samanlaista kuin vanha hyvä malli-näkymä-ohjain (MVC).
Koska Elm on puhdas toiminnallinen ohjelmointikieli, kaikki tiedot ovat muuttumattomia, mikä tarkoittaa, että mallia ei voida muuttaa. Sen sijaan voimme luoda uuden mallin, joka perustuu edelliseen, jonka teemme päivitystoimintojen avulla.
Miksi se on niin hienoa?
Muuttamattomien tietojen avulla toiminnoilla ei voi enää olla sivuvaikutuksia. Tämä avaa mahdollisuuksien maailman, mukaan lukien Elmin aikamatkojen virheenkorjaus, josta keskustelemme pian.
Näkymät esitetään aina, kun mallin muutos edellyttää näkymän muutosta, ja meillä on aina sama tulos mallin samoille tiedoille - suunnilleen samalla tavalla kuin puhdas funktio palauttaa aina saman tuloksen mallille samat syöteargumentit.
Mennään eteenpäin ja toteutetaan HTML-näkymä ostoskorisovelluksellemme.
Jos tunnet Reactin, tämä on jotain, josta varmasti arvot: Elmillä on paketti vain HTML-elementtien määrittelemiseksi. Tämän avulla voit toteuttaa näkymän Elmillä tarvitsematta luottaa ulkoisiin mallikieliin.
HTML-elementtien kääreitä on saatavana kohdassa Html
paketti:
import Html exposing (Html, button, table, caption, thead, tbody, tfoot, tr, td, th, text, section, p, h1)
Kaikki Elm-ohjelmat alkavat suorittamalla päätoiminnon:
type alias Stock = List Product type alias Model = { cart : Cart, stock : Stock } main = Html.beginnerProgram { model = Model [] [ Product 'Bicycle' 100.50 , Product 'Rocket' 15.36 , Product 'Biscuit' 21.15 ] , view = view , update = update }
Tässä päätoiminto alustaa Elm-ohjelman joillakin malleilla, näkymällä ja päivitystoiminnolla. Olemme määrittäneet muutamia tuotteita ja niiden hintoja. Yksinkertaisuuden vuoksi oletamme, että meillä on rajoittamaton määrä tuotteita.
Päivitystoiminto herättää sovelluksemme eloon.
Se vie viestin ja päivittää tilan viestin sisällön perusteella. Määritämme sen funktiona, joka ottaa kaksi parametria (viesti ja nykyisen mallin) ja palauttaa uuden mallin:
type Msg = Add Product update : Msg -> Model -> Model update msg model = case msg of Add product -> cart = add model.cart product
Toistaiseksi käsittelemme yksittäistä tapausta, kun viesti on Add product
, missä kutsumme add
menetelmä cart
product
kanssa.
Päivitystoiminto kasvaa Elm-ohjelman monimutkaisuuden kasvaessa.
Seuraavaksi määritämme ostoskorimme näkymän.
Näkymä on toiminto, joka muuntaa mallin HTML-esitykseksi. Se ei kuitenkaan ole vain staattinen HTML. HTML-generaattori pystyy lähettämään viestejä takaisin sovellukselle käyttäjien eri vuorovaikutusten ja tapahtumien perusteella.
view : Model -> Html Msg view model = section [style [('margin', '10px')]] [ stockView model.stock , cartView model.cart ] stockView : Stock -> Html Msg stockView stock = table [] [ caption [] [ h1 [] [ text 'Stock' ] ] , thead [] [ tr [] [ th [align 'left', width 100] [ text 'Name' ] , th [align 'right', width 100] [ text 'Price' ] , th [width 100] [] ] ] , tbody [] (map stockProductView stock) ] stockProductView : Product -> Html Msg stockProductView product = tr [] [ td [] [ text product.name ] , td [align 'right'] [ text (' $' ++ toString product.price) ] , td [] [ button [ onClick (Add product) ] [ text 'Add to Cart' ] ] ]
Html
package tarjoaa kääreitä kaikille yleisesti käytetyille elementeille funktioina, joilla on tutut nimet (esim. funktio section
luo elementin).
style
funktio, osa Html.Attributes
paketti, luo objektin, joka voidaan siirtää section
toiminto asettaa tyylimääritteen tuloksena olevalle elementille.
On parempi jakaa näkymä erillisiin toimintoihin uudelleenkäytettävyyden parantamiseksi.
Asioiden yksinkertaistamiseksi olemme upottaneet CSS: n ja joitain asettelumääritteitä suoraan näkymäkoodiin. On kuitenkin olemassa kirjastoja, jotka yksinkertaistavat muotoiluprosessi HTML-elementtisi Elm-koodista.
Huomaa button
katkelman loppupuolella ja miten olemme yhdistäneet viestin Add product
painikkeen napsautustapahtumaan.
Elm huolehtii kaiken tarvittavan koodin luomisesta soittopyynnön sitomiseksi varsinaiseen tapahtumaan ja päivitystoiminnon luomisen ja kutsumisen asiaankuuluvilla parametreilla.
Lopuksi meidän on pantava täytäntöön viimeinen näkemyksemme:
cartView : Cart -> Html Msg cartView cart = if isEmpty cart then p [] [ text 'Cart is empty' ] else table [] [ caption [] [ h1 [] [ text 'Cart' ]] , thead [] [ tr [] [ th [ align 'left', width 100 ] [ text 'Name' ] , th [ align 'right', width 100 ] [ text 'Price' ] , th [ align 'center', width 50 ] [ text 'Qty' ] , th [ align 'right', width 100 ] [ text 'Subtotal' ] ] ] , tbody [] (map cartProductView cart) , tfoot [] [ tr [style [('font-weight', 'bold')]] [ td [ align 'right', colspan 4 ] [ text ('$' ++ toString (subtotal cart)) ] ] ] ] cartProductView : Item -> Html Msg cartProductView item = tr [] [ td [] [ text item.product.name ] , td [ align 'right' ] [ text ('$' ++ toString item.product.price) ] , td [ align 'center' ] [ text (toString item.qty) ] , td [ align 'right' ] [ text ('$' ++ toString (itemSubtotal item)) ] ]
Tässä olemme määrittäneet näkymämme toisen osan, jossa renderöimme ostoskorimme sisällön. Vaikka näkymäfunktio ei lähetä viestiä, sillä on kuitenkin oltava palautustyyppi Html Msg
saada näkymä.
Näkymä paitsi luetteloi ostoskorin sisällön, mutta myös laskee ja hahmottaa välisumman ostoskorin sisällön perusteella.
Löydät tämän Elm-ohjelman koko koodin tässä .
Jos olisit suorita Elm-ohjelma nyt , näet jotain tällaista:
Kuinka kaikki toimii?
Ohjelma alkaa melko tyhjällä tilassa main
toiminto - tyhjä kori, jossa on muutama kovakoodattu tuote.
Aina kun napsautetaan Lisää ostoskoriin -painiketta, päivitystoiminnolle lähetetään viesti, joka päivittää ostoskorin vastaavasti ja luo uuden mallin. Aina kun malli päivitetään, Elm käyttää näkymäfunktioita HTML-puun uudistamiseksi.
Koska Elm käyttää Reactin tapaan virtuaalista DOM-lähestymistapaa, käyttöliittymän muutokset tehdään vain tarvittaessa, mikä varmistaa nopean suorituskyvyn.
Hirmu on staattisesti kirjoitettu, mutta kääntäjä voi tarkistaa paljon enemmän kuin vain tyypit.
Tehdään muutos Msg
kirjoita ja katso kuinka kääntäjä reagoi siihen:
type Msg = Add Product | ChangeQty Product String
Olemme määrittäneet toisenlaisen viestin - jotain, joka muuttaisi tuotteen määrää ostoskorissa. Yritetään suorittaa ohjelma uudelleen käsittelemättä tätä viestiä päivitystoiminnossa, kuitenkin seuraava virhe:
Huomaa, että edellisessä osassa käytimme merkkijonoa määrän arvon tyypiksi. Tämä johtuu siitä, että arvo tulee anelementistä, joka on tyypin merkkijono.
Lisätään uusi funktio changeQty
kohtaan Cart
moduuli. On aina parempi pitää toteutus moduulin sisällä, jotta sitä voidaan muuttaa myöhemmin tarvittaessa moduulin sovellusliittymää muuttamatta.
Change quantity of the product in the cart. Look at the result of the function. It uses Result type. The Result type has two parameters: for bad and for good result. So the result will be Error 'msg' or a Cart with updated product quantity. - changeQty : Cart -> Product -> Int -> Result String Cart {-| If the quantity parameter is zero the product will be removed completely from the cart. If the quantity parameter is greater then zero the quantity of the product will be updated. Otherwise (qty item.product /= product) cart) else if qty > 0 then Result.Ok (map (item -> if item.product == product then item else item) cart) else Result.Err ('Wrong negative quantity used: ' ++ (toString qty))
Meidän ei pitäisi tehdä mitään oletuksia toiminnon käytöstä. Voimme olla varmoja, että parametri qty
sisältää Int
mutta arvo voi olla mikä tahansa. Siksi tarkistamme arvon ja ilmoita virheestä kun se on virheellinen.
Päivitämme myös update
toimii vastaavasti:
update msg model = case msg of Add product -> cart = add model.cart product ChangeQty product str -> case toInt str of Ok qty -> case changeQty model.cart product qty of Ok cart -> model Err msg -> model -- do nothing, the wrong input Err msg -> model -- do nothing, the wrong quantity
Muunna merkkijono quantity
parametri viestistä numeroon ennen sen käyttöä. Jos merkkijonossa on virheellinen numero, ilmoitamme siitä virheeksi.
Tässä pidämme mallia muuttumattomana, kun tapahtuu virhe. Vaihtoehtoisesti voisimme vain päivittää mallin tavalla, joka ilmoittaa virheestä viestinä näkymässä, jonka käyttäjä näkee:
type alias Model = { cart : Cart, stock : Stock, error : Maybe String } main = Html.beginnerProgram { model = Model [] -- empty cart [ Product 'Bicycle' 100.50 -- stock , Product 'Rocket' 15.36 , Product 'Bisquit' 21.15 ] Nothing -- error (no error at beginning) , view = view , update = update } update msg model = case msg of Add product -> cart = add model.cart product ChangeQty product str -> case toInt str of Ok qty -> case changeQty model.cart product qty of Ok cart -> model Err msg -> error = Just msg Err msg -> model
Käytämme tyyppiä Maybe String
mallimme virhemääritteelle. Ehkä on toinen tyyppi, johon voi olla joko Nothing
tai tietyn tyyppinen arvo.
Kun olet päivittänyt näkymätoiminnon seuraavasti:
view model = section [style [('margin', '10px')]] [ stockView model.stock , cartView model.cart , errorView model.error ] errorView : Maybe String -> Html Msg errorView error = case error of Just msg -> p [style [('color', 'red')]] [ text msg ] Nothing -> p [] []
Sinun pitäisi nähdä tämä:
Yritä syöttää ei-numeerinen arvo (esim. '1a') johtaisi virheilmoitukseen, kuten yllä olevassa kuvakaappauksessa näytetään.
Elmillä on oma arkisto avoimen lähdekoodin paketteja. Elmin paketinhallinnan avulla on helppoa hyödyntää tätä pakettipakettia. Vaikka arkiston koko ei ole verrattavissa joihinkin muihin kypsiin ohjelmointikieliin, kuten Python tai PHP, Elm-yhteisö työskentelee ahkerasti päivittäisten pakettien lisäämiseksi.
Huomaa, kuinka mielestämme renderoidut hintojen desimaalit ovat epäjohdonmukaisia?
Korvataan toString
: n naiivi käyttö jotain parempaa arkistosta: numero-jalava .
cartProductView item = tr [] [ td [] [ text item.product.name ] , td [ align 'right' ] [ text (formatPrice item.product.price) ] , td [ align 'center' ] [ input [ value (toString item.qty) , onInput (ChangeQty item.product) , size 3 --, type' 'number' ] [] ] , td [ align 'right' ] [ text (formatPrice (itemSubtotal item)) ] ] formatPrice : Float -> String formatPrice price = format 'Tee Web-käyttöliittymästä luotettava Elmin kanssa
Kuinka monta kertaa olet yrittänyt selvittää web-käyttöliittymääsi ja löytänyt itsesi sotkeutuneena monimutkaisten tapahtumaketjujen käsittelevään koodiin?
Yrititkö koskaan muokata koodia käyttöliittymälle, joka käsittelee paljon komponentteja, jotka on rakennettu jQueryllä, Backbone.js: llä tai muilla suosituilla JavaScript-kehyksillä?
Yksi tuskallisimmista asioista näissä skenaarioissa on yrittää seurata useita määrittelemättömiä tapahtumasarjoja sekä ennakoida ja korjata kaikki nämä käyttäytymismallit. Yksinkertaisesti painajainen!
Olen aina etsinyt tapoja välttää tämä helvetillinen osa web-käyttöliittymäkehitystä. Backbone.js toimi minulle hyvin tässä suhteessa antamalla web-käyttöliittymille rakenteen, josta he ovat puuttuneet pitkään. Mutta kun otetaan huomioon se, että se tarvitsee tehdä mitättömimpiä asioita, se ei osoittautunut paljon paremmaksi.
Sitten tapasin Jalava .
Elm on staattisesti kirjoitettu toiminnallinen kieli, joka perustuu Haskell-ohjelmointikieleen, mutta a yksinkertaisempi erittely . Kääntäjä (myös rakennettu Haskellin avulla) jäsentää Elm-koodin ja kääntää sen JavaScriptiksi.
Elm rakennettiin alun perin käyttöliittymän kehittämistä varten, mutta ohjelmistosuunnittelijat ovat löytäneet tapoja käyttää sitä myös palvelinpuolen ohjelmointiin.
Tässä artikkelissa on yleiskatsaus siitä, kuinka Elm voi muuttaa tapaa, jolla ajattelemme web-käyttöliittymän kehitystä, sekä johdanto tämän toiminnallisen ohjelmointikielen perusteisiin. Tässä opetusohjelmassa kehitämme yksinkertaisen ostoskorin kaltaisen sovelluksen Elm-sovelluksen avulla.
Elm lupaa monia etuja, joista suurin osa on erittäin hyödyllisiä puhtaan web-käyttöliittymän arkkitehtuurin saavuttamiseksi. Elm tarjoaa paremmat HTML-renderoinnin suorituskyvyn edut muiden suosittujen kehysten (jopa React.js) yli. Lisäksi Elm sallii kehittäjien kirjoittaa koodia, joka käytännössä ei tuota suurinta osaa ajonaikaisia poikkeuksia, jotka vaivaavat dynaamisesti kirjoitettuja kieliä, kuten JavaScriptiä.
Kääntäjä päättelee tyypit automaattisesti ja antaa ystävällisiä virheitä, mikä saa kehittäjän tietämään mahdolliset ongelmat ennen ajonaikaa.
NoRedInkillä on 36 000 Elm-riviä, ja yli vuoden tuotannon jälkeen se ei ole vieläkään tuottanut yhtä ajonaikaista poikkeusta. [ Lähde ]
Sinun ei tarvitse muuntaa koko olemassa olevaa JavaScript-sovellustasi vain, jotta voit kokeilla Elmia. Erinomaisen JavaScript-yhteentoimivuutensa avulla voit jopa ottaa vain pienen osan olemassa olevasta sovelluksestasi ja kirjoittaa sen uudelleen Elmiin.
Elmillä on myös erinomainen dokumentointi joka paitsi antaa sinulle perusteellisen kuvauksen sen tarjonnasta, mutta antaa myös oikean oppaan web-käyttöliittymän rakentamiseen Elm-arkkitehtuuri - jotain, joka sopii mainiosti modulaarisuuteen, koodin uudelleenkäyttöön ja testaukseen.
Aloitetaan hyvin lyhyellä katkelmalla Elm-koodista:
import List exposing (..) cart = [] item product quantity = { product = product, qty = quantity } product name price = { name = name, price = price } add cart product = if isEmpty (filter (item -> item.product == product) cart) then append cart [item product 1] else cart subtotal cart = -- we want to calculate cart subtotal sum (map (item -> item.product.price * toFloat item.qty) cart)
Mikä tahansa teksti, jota edeltää
--
on kommentti Elm .
Tässä määritellään ostoskori tavaraluettelona, jossa jokainen tuote on tietue, jolla on kaksi arvoa (tuote, jota se vastaa, ja määrä). Jokainen tuote on levy, jolla on nimi ja hinta.
Tuotteen lisääminen ostoskoriin edellyttää tarkistamista, onko tuote jo ostoskorissa.
Jos se tapahtuu, emme tee mitään; muuten lisäämme tuotteen ostoskoriin uutena tuotteena. Tarkistamme, onko tuote jo ostoskorissa suodattamalla luettelo, sovittamalla jokainen tuote tuotteeseen ja tarkistamalla, onko tuloksena oleva suodatettu luettelo tyhjä.
Välisumman laskemiseksi toistetaan ostoskorin kohteet, löydetään vastaava tuotemäärä ja hinta ja summataan kaikki yhteen.
Tämä on yhtä minimalistista kuin kärry ja siihen liittyvät toiminnot voivat saada. Aloitamme tästä koodista ja parannamme sitä askel askeleelta tekemällä siitä kokonaisen verkkokomponentin tai ohjelman Elmin termein.
Aloitetaan lisäämällä tyypit ohjelmasi eri tunnisteisiin. Hirvi kykenee päättelemään tyypit itse, mutta hyödyntämään Elmistä ja sen kääntäjistä on suositeltavaa, että tyypit ilmoitetaan nimenomaisesti.
module Cart1 exposing ( Cart, Item, Product , add, subtotal , itemSubtotal ) -- This is module and its API definition We build an easy shopping cart. @docs Cart, Item, Product, add, subtotal, itemSubtotal - import List exposing (..) -- we need list manipulation functions Cart is a list of items. - type alias Cart = List Item - type alias Item = { product : Product, qty : Int } Product is a record with name and price - type alias Product = { name : String, price : Float } We want to add stuff to a cart. This is a function definition, it takes a cart, a product to add and returns new cart - add : Cart -> Product -> Cart This is an implementation of the 'add' function. Just append product item to the cart if there is no such product in the cart listed. Do nothing if the product exists. - add cart product = if isEmpty (filter (item -> item.product == product) cart) then append cart [Item product 1] else cart I need to calculate cart subtotal. The function takes a cart and returns float. - subtotal : Cart -> Float - subtotal cart = sum (map itemSubtotal cart) Item subtotal takes item and return the subtotal float. - itemSubtotal : Item -> Float Subtotal is based on product's price and quantity. - itemSubtotal item = item.product.price * toFloat item.qty
Tyyppimerkinnöillä kääntäjä voi nyt tarttua ongelmiin, jotka muuten olisivat johtaneet ajonaikaisiin poikkeuksiin.
Elm ei kuitenkaan pysähdy siihen. Hirmuarkkitehtuuri opastaa kehittäjiä yksinkertaisen mallin avulla web-käyttöliittymien jäsentämiseen, ja se tapahtuu käsitteiden kautta, jotka useimmat kehittäjät ovat jo tunteneet:
Jos ajattelet koodisi osaa, joka käsittelee päivitykset ohjaimena sinulla on jotain hyvin samanlaista kuin vanha hyvä malli-näkymä-ohjain (MVC).
Koska Elm on puhdas toiminnallinen ohjelmointikieli, kaikki tiedot ovat muuttumattomia, mikä tarkoittaa, että mallia ei voida muuttaa. Sen sijaan voimme luoda uuden mallin, joka perustuu edelliseen, jonka teemme päivitystoimintojen avulla.
Miksi se on niin hienoa?
Muuttamattomien tietojen avulla toiminnoilla ei voi enää olla sivuvaikutuksia. Tämä avaa mahdollisuuksien maailman, mukaan lukien Elmin aikamatkojen virheenkorjaus, josta keskustelemme pian.
Näkymät esitetään aina, kun mallin muutos edellyttää näkymän muutosta, ja meillä on aina sama tulos mallin samoille tiedoille - suunnilleen samalla tavalla kuin puhdas funktio palauttaa aina saman tuloksen mallille samat syöteargumentit.
Mennään eteenpäin ja toteutetaan HTML-näkymä ostoskorisovelluksellemme.
Jos tunnet Reactin, tämä on jotain, josta varmasti arvot: Elmillä on paketti vain HTML-elementtien määrittelemiseksi. Tämän avulla voit toteuttaa näkymän Elmillä tarvitsematta luottaa ulkoisiin mallikieliin.
HTML-elementtien kääreitä on saatavana kohdassa Html
paketti:
import Html exposing (Html, button, table, caption, thead, tbody, tfoot, tr, td, th, text, section, p, h1)
Kaikki Elm-ohjelmat alkavat suorittamalla päätoiminnon:
type alias Stock = List Product type alias Model = { cart : Cart, stock : Stock } main = Html.beginnerProgram { model = Model [] [ Product 'Bicycle' 100.50 , Product 'Rocket' 15.36 , Product 'Biscuit' 21.15 ] , view = view , update = update }
Tässä päätoiminto alustaa Elm-ohjelman joillakin malleilla, näkymällä ja päivitystoiminnolla. Olemme määrittäneet muutamia tuotteita ja niiden hintoja. Yksinkertaisuuden vuoksi oletamme, että meillä on rajoittamaton määrä tuotteita.
Päivitystoiminto herättää sovelluksemme eloon.
Se vie viestin ja päivittää tilan viestin sisällön perusteella. Määritämme sen funktiona, joka ottaa kaksi parametria (viesti ja nykyisen mallin) ja palauttaa uuden mallin:
type Msg = Add Product update : Msg -> Model -> Model update msg model = case msg of Add product -> cart = add model.cart product
Toistaiseksi käsittelemme yksittäistä tapausta, kun viesti on Add product
, missä kutsumme add
menetelmä cart
product
kanssa.
Päivitystoiminto kasvaa Elm-ohjelman monimutkaisuuden kasvaessa.
Seuraavaksi määritämme ostoskorimme näkymän.
Näkymä on toiminto, joka muuntaa mallin HTML-esitykseksi. Se ei kuitenkaan ole vain staattinen HTML. HTML-generaattori pystyy lähettämään viestejä takaisin sovellukselle käyttäjien eri vuorovaikutusten ja tapahtumien perusteella.
view : Model -> Html Msg view model = section [style [('margin', '10px')]] [ stockView model.stock , cartView model.cart ] stockView : Stock -> Html Msg stockView stock = table [] [ caption [] [ h1 [] [ text 'Stock' ] ] , thead [] [ tr [] [ th [align 'left', width 100] [ text 'Name' ] , th [align 'right', width 100] [ text 'Price' ] , th [width 100] [] ] ] , tbody [] (map stockProductView stock) ] stockProductView : Product -> Html Msg stockProductView product = tr [] [ td [] [ text product.name ] , td [align 'right'] [ text (' $' ++ toString product.price) ] , td [] [ button [ onClick (Add product) ] [ text 'Add to Cart' ] ] ]
Html
package tarjoaa kääreitä kaikille yleisesti käytetyille elementeille funktioina, joilla on tutut nimet (esim. funktio section
luo elementin).
style
funktio, osa Html.Attributes
paketti, luo objektin, joka voidaan siirtää section
toiminto asettaa tyylimääritteen tuloksena olevalle elementille.
On parempi jakaa näkymä erillisiin toimintoihin uudelleenkäytettävyyden parantamiseksi.
Asioiden yksinkertaistamiseksi olemme upottaneet CSS: n ja joitain asettelumääritteitä suoraan näkymäkoodiin. On kuitenkin olemassa kirjastoja, jotka yksinkertaistavat muotoiluprosessi HTML-elementtisi Elm-koodista.
Huomaa button
katkelman loppupuolella ja miten olemme yhdistäneet viestin Add product
painikkeen napsautustapahtumaan.
Elm huolehtii kaiken tarvittavan koodin luomisesta soittopyynnön sitomiseksi varsinaiseen tapahtumaan ja päivitystoiminnon luomisen ja kutsumisen asiaankuuluvilla parametreilla.
Lopuksi meidän on pantava täytäntöön viimeinen näkemyksemme:
cartView : Cart -> Html Msg cartView cart = if isEmpty cart then p [] [ text 'Cart is empty' ] else table [] [ caption [] [ h1 [] [ text 'Cart' ]] , thead [] [ tr [] [ th [ align 'left', width 100 ] [ text 'Name' ] , th [ align 'right', width 100 ] [ text 'Price' ] , th [ align 'center', width 50 ] [ text 'Qty' ] , th [ align 'right', width 100 ] [ text 'Subtotal' ] ] ] , tbody [] (map cartProductView cart) , tfoot [] [ tr [style [('font-weight', 'bold')]] [ td [ align 'right', colspan 4 ] [ text ('$' ++ toString (subtotal cart)) ] ] ] ] cartProductView : Item -> Html Msg cartProductView item = tr [] [ td [] [ text item.product.name ] , td [ align 'right' ] [ text ('$' ++ toString item.product.price) ] , td [ align 'center' ] [ text (toString item.qty) ] , td [ align 'right' ] [ text ('$' ++ toString (itemSubtotal item)) ] ]
Tässä olemme määrittäneet näkymämme toisen osan, jossa renderöimme ostoskorimme sisällön. Vaikka näkymäfunktio ei lähetä viestiä, sillä on kuitenkin oltava palautustyyppi Html Msg
saada näkymä.
Näkymä paitsi luetteloi ostoskorin sisällön, mutta myös laskee ja hahmottaa välisumman ostoskorin sisällön perusteella.
Löydät tämän Elm-ohjelman koko koodin tässä .
Jos olisit suorita Elm-ohjelma nyt , näet jotain tällaista:
Kuinka kaikki toimii?
Ohjelma alkaa melko tyhjällä tilassa main
toiminto - tyhjä kori, jossa on muutama kovakoodattu tuote.
Aina kun napsautetaan Lisää ostoskoriin -painiketta, päivitystoiminnolle lähetetään viesti, joka päivittää ostoskorin vastaavasti ja luo uuden mallin. Aina kun malli päivitetään, Elm käyttää näkymäfunktioita HTML-puun uudistamiseksi.
Koska Elm käyttää Reactin tapaan virtuaalista DOM-lähestymistapaa, käyttöliittymän muutokset tehdään vain tarvittaessa, mikä varmistaa nopean suorituskyvyn.
Hirmu on staattisesti kirjoitettu, mutta kääntäjä voi tarkistaa paljon enemmän kuin vain tyypit.
Tehdään muutos Msg
kirjoita ja katso kuinka kääntäjä reagoi siihen:
type Msg = Add Product | ChangeQty Product String
Olemme määrittäneet toisenlaisen viestin - jotain, joka muuttaisi tuotteen määrää ostoskorissa. Yritetään suorittaa ohjelma uudelleen käsittelemättä tätä viestiä päivitystoiminnossa, kuitenkin seuraava virhe:
Huomaa, että edellisessä osassa käytimme merkkijonoa määrän arvon tyypiksi. Tämä johtuu siitä, että arvo tulee anelementistä, joka on tyypin merkkijono.
Lisätään uusi funktio changeQty
kohtaan Cart
moduuli. On aina parempi pitää toteutus moduulin sisällä, jotta sitä voidaan muuttaa myöhemmin tarvittaessa moduulin sovellusliittymää muuttamatta.
Change quantity of the product in the cart. Look at the result of the function. It uses Result type. The Result type has two parameters: for bad and for good result. So the result will be Error 'msg' or a Cart with updated product quantity. - changeQty : Cart -> Product -> Int -> Result String Cart {-| If the quantity parameter is zero the product will be removed completely from the cart. If the quantity parameter is greater then zero the quantity of the product will be updated. Otherwise (qty item.product /= product) cart) else if qty > 0 then Result.Ok (map (item -> if item.product == product then item else item) cart) else Result.Err ('Wrong negative quantity used: ' ++ (toString qty))
Meidän ei pitäisi tehdä mitään oletuksia toiminnon käytöstä. Voimme olla varmoja, että parametri qty
sisältää Int
mutta arvo voi olla mikä tahansa. Siksi tarkistamme arvon ja ilmoita virheestä kun se on virheellinen.
Päivitämme myös update
toimii vastaavasti:
update msg model = case msg of Add product -> cart = add model.cart product ChangeQty product str -> case toInt str of Ok qty -> case changeQty model.cart product qty of Ok cart -> model Err msg -> model -- do nothing, the wrong input Err msg -> model -- do nothing, the wrong quantity
Muunna merkkijono quantity
parametri viestistä numeroon ennen sen käyttöä. Jos merkkijonossa on virheellinen numero, ilmoitamme siitä virheeksi.
Tässä pidämme mallia muuttumattomana, kun tapahtuu virhe. Vaihtoehtoisesti voisimme vain päivittää mallin tavalla, joka ilmoittaa virheestä viestinä näkymässä, jonka käyttäjä näkee:
type alias Model = { cart : Cart, stock : Stock, error : Maybe String } main = Html.beginnerProgram { model = Model [] -- empty cart [ Product 'Bicycle' 100.50 -- stock , Product 'Rocket' 15.36 , Product 'Bisquit' 21.15 ] Nothing -- error (no error at beginning) , view = view , update = update } update msg model = case msg of Add product -> cart = add model.cart product ChangeQty product str -> case toInt str of Ok qty -> case changeQty model.cart product qty of Ok cart -> model Err msg -> error = Just msg Err msg -> model
Käytämme tyyppiä Maybe String
mallimme virhemääritteelle. Ehkä on toinen tyyppi, johon voi olla joko Nothing
tai tietyn tyyppinen arvo.
Kun olet päivittänyt näkymätoiminnon seuraavasti:
view model = section [style [('margin', '10px')]] [ stockView model.stock , cartView model.cart , errorView model.error ] errorView : Maybe String -> Html Msg errorView error = case error of Just msg -> p [style [('color', 'red')]] [ text msg ] Nothing -> p [] []
Sinun pitäisi nähdä tämä:
Yritä syöttää ei-numeerinen arvo (esim. '1a') johtaisi virheilmoitukseen, kuten yllä olevassa kuvakaappauksessa näytetään.
Elmillä on oma arkisto avoimen lähdekoodin paketteja. Elmin paketinhallinnan avulla on helppoa hyödyntää tätä pakettipakettia. Vaikka arkiston koko ei ole verrattavissa joihinkin muihin kypsiin ohjelmointikieliin, kuten Python tai PHP, Elm-yhteisö työskentelee ahkerasti päivittäisten pakettien lisäämiseksi.
Huomaa, kuinka mielestämme renderoidut hintojen desimaalit ovat epäjohdonmukaisia?
Korvataan toString
: n naiivi käyttö jotain parempaa arkistosta: numero-jalava .
cartProductView item = tr [] [ td [] [ text item.product.name ] , td [ align 'right' ] [ text (formatPrice item.product.price) ] , td [ align 'center' ] [ input [ value (toString item.qty) , onInput (ChangeQty item.product) , size 3 --, type' 'number' ] [] ] , td [ align 'right' ] [ text (formatPrice (itemSubtotal item)) ] ] formatPrice : Float -> String formatPrice price = format '$0,0.00' price
Käytämme format
-toiminto tästä numeropaketista. Tämä muotoilisi numerot tavalliseen tapaan valuutat:
100.5 -> $100.50 15.36 -> $15.36 21.15 -> $21.15
Kun julkaiset paketin Elm-arkistoon, dokumentaatio luodaan automaattisesti koodin kommenttien perusteella. Voit nähdä sen toiminnassa tutustumalla Cart-moduulin dokumentaatioon tässä . Kaikki nämä on luotu tässä tiedostossa olevista kommenteista: Cart.elm .
Kääntäjä itse havaitsee ja ilmoittaa ilmeisimmät ongelmat. Mikään sovellus ei kuitenkaan ole suojattu loogisilta virheiltä.
Koska kaikki Elmin tiedot ovat muuttumattomia ja kaikki tapahtuu päivitystoiminnolle välitettyjen viestien kautta, Elm-ohjelman koko virta voidaan esittää sarjana mallimuutoksia. Debuggerille Elm on kuin vuoropohjainen strategiapeli. Tämän avulla virheenkorjaaja voi suorittaa todella upeita tekoja, kuten matkustaa ajan myötä. Se voi liikkua edestakaisin ohjelmassa läpi siirtymällä eri mallimuutosten välillä, jotka tapahtuivat ohjelman elinkaaren aikana.
Voit oppia lisää virheenkorjauksesta tässä .
Joten sanotte, että olemme rakentaneet mukavan lelun, mutta voiko Hammasta käyttää johonkin vakavaan? Ehdottomasti.
Yhdistetään ostoskorin käyttöliittymä asynkroniseen käyttöliittymään. Jotta se olisi mielenkiintoinen, toteutamme jotain erityistä. Oletetaan, että haluamme tarkastaa kaikki kärryt ja niiden sisällön reaaliajassa. Todellisessa elämässä voisimme käyttää tätä lähestymistapaa tuodaksemme ylimääräisiä markkinointi- / myyntimahdollisuuksia verkkokauppaan tai markkinapaikkaan, tai tehdä joitakin ehdotuksia käyttäjälle tai arvioida tarvittavat varastoresurssit ja paljon muuta.
Joten varastamme ostoskorin asiakaspuolelle ja ilmoitamme palvelimelle myös jokaisesta ostoskorista reaaliajassa.
Jotta asiat pysyisivät yksinkertaisina, toteutamme taustamme käyttämällä Pythonia. Löydät taustakoodin koko koodin tässä .
Se on yksinkertainen verkkopalvelin, joka käyttää WebSocketia ja seuraa ostoskorin sisältöä muistissa. Yksinkertaisuuden vuoksi renderöimme kaikkien muiden ostoskorin samalla sivulla. Tämä voidaan helposti toteuttaa erillisellä sivulla tai jopa erillisenä Elm-ohjelmana. Toistaiseksi jokainen käyttäjä voi nähdä yhteenvedon muiden käyttäjien ostoskorista.
Kun käyttöliittymä on paikallaan, meidän on nyt päivitettävä Elm-sovelluksemme lähettääksesi ja vastaanottaaksesi ostoskoripäivityksiä palvelimelle. Käytämme JSONia koodaamaan hyötykuormamme, jota Elmillä on erinomainen tuki.
Toteutamme kooderin muuntamaan Elm-tietomallimme JSON-merkkijonoesitykseksi. Tätä varten meidän on käytettävä Json. Koodaa kirjasto .
module CartEncoder exposing (cart) import Cart2 exposing (Cart, Item, Product) import List exposing (map) import Json.Encode exposing (..) product : Product -> Value product product = object [ ('name', string product.name) , ('price', float product.price) ] item : Item -> Value item item = object [ ('product', product item.product) , ('qty', int item.qty) ] cart : Cart -> Value cart cart = list (map item cart)
Kirjasto tarjoaa joitain toimintoja (kuten string
, int
, float
, object
jne.), Jotka ottavat Elm-objektit ja tekevät niistä JSON-koodatut merkkijonot.
Dekooderin käyttöönotto on hieman hankalampi, koska kaikilla Elm-tiedoilla on tyyppejä, ja meidän on määriteltävä, mikä JSON-arvo on muunnettava mihin tyyppiin:
module CartDecoder exposing (cart) import Cart2 exposing (Cart, Item, Product) -- decoding for Cart import Json.Decode exposing (..) -- will decode cart from string cart : Decoder (Cart) cart = list item -- decoder for cart is a list of items item : Decoder (Item) item = object2 Item -- decoder for item is an object with two properties: ('product' := product) -- 1) 'product' of product ('qty' := int) -- 2) 'qty' of int product : Decoder (Product) product = object2 Product -- decoder for product also an object with two properties: ('name' := string) -- 1) 'name' ('price' := float) -- 2) 'price'
Koska lopullinen Elm-koodi on vähän pidempi, löydät sen tässä . Tässä on yhteenveto käyttöliittymäsovellukseen tehdyistä muutoksista:
Olemme käärineet alkuperäisen update
toiminto toiminnolla, joka lähettää muutoksia ostoskorin sisältöön taustapuolelle joka kerta kun ostoskoria päivitetään:
updateOnServer msg model = let (newModel, have_to_send) = update msg model in case have_to_send of True -> -- send updated cart to server (!) newModel [ WebSocket.send server (encode 0 (CartEncoder.cart newModel.cart)) ] False -> -- do nothing (newModel, Cmd.none)
Olemme myös lisänneet ylimääräisen viestityypin ConsumerCarts String
saada päivityksiä palvelimelta ja päivittää paikallinen malli vastaavasti.
Näkymä on päivitetty muokkaamaan muiden kärryjen yhteenveto consumersCartsView
-painikkeella toiminto.
WebSocket-yhteys on muodostettu tilaamaan taustakuva kuuntelemaan muiden kärryjen muutoksia.
subscriptions : Model -> Sub Msg subscriptions model = WebSocket.listen server ConsumerCarts server = 'ws://127.0.0.1:8765'
Olemme myös päivittäneet päätoimintomme. Käytämme nyt Html.program
ylimääräisellä init
ja subscriptions
parametrit. init
määrittää ohjelman alkuperäisen mallin ja subscription
määrittää luettelon tilauksista.
Tilaus on tapa, jolla voimme käskeä Elmiä kuuntelemaan muutoksia tietyillä kanavilla ja välittämään nämä viestit update
toiminto.
main = Html.program { init = init , view = view , update = updateOnServer , subscriptions = subscriptions } init = ( Model [] -- empty cart [ Product 'Bicycle' 100.50 -- stock , Product 'Rocket' 15.36 , Product 'Bisquit' 21.15 ] Nothing -- error (no error at beginning) [] -- consumer carts list is empty , Cmd.none)
Lopuksi olemme käsitelleet tapaa, jolla puramme ConsumerCarts-viestin, jonka saamme palvelimelta. Tämä varmistaa, että ulkoisesta lähteestä saamamme tiedot eivät riko sovellusta.
ConsumerCarts message -> case decodeString (Json.Decode.list CartDecoder.cart) message of Ok carts -> ( consumer_carts = carts , False) Err msg -> ( model , False)
Elm on erilainen. Se vaatii kehittäjää ajattelemaan toisin.
Jokainen, joka tulee JavaScriptiä ja vastaavia kieliä edustavalle alueelle, yrittää oppia Elmin tapaa tehdä asioita.
Viime kädessä Elm tarjoaa kuitenkin jotain, mitä muut kehykset - jopa suosituimmat - usein taistelevat. Nimittäin se tarjoaa keinon rakentaa vankkoja käyttöliittymäsovelluksia sotkeutumatta valtavaan yksityiskohtaiseen koodiin.
Elm myös abstraktio monista JavaScriptin aiheuttamia vaikeuksia yhdistämällä älykäs kääntäjä tehokkaaseen virheenkorjaimeen.
Elm on sitä mitä etupään kehittäjät ovat kaipanneet niin kauan. Nyt kun olet nähnyt sen toiminnassa, ota se itse pyörimään ja nauti eduista rakentamalla seuraava web-projekti kaupungissa Elm.
Käytämme format
-toiminto tästä numeropaketista. Tämä muotoilisi numerot tavalliseen tapaan valuutat:
100.5 -> 0.50 15.36 -> .36 21.15 -> .15
Kun julkaiset paketin Elm-arkistoon, dokumentaatio luodaan automaattisesti koodin kommenttien perusteella. Voit nähdä sen toiminnassa tutustumalla Cart-moduulin dokumentaatioon tässä . Kaikki nämä on luotu tässä tiedostossa olevista kommenteista: Cart.elm .
Kääntäjä itse havaitsee ja ilmoittaa ilmeisimmät ongelmat. Mikään sovellus ei kuitenkaan ole suojattu loogisilta virheiltä.
Koska kaikki Elmin tiedot ovat muuttumattomia ja kaikki tapahtuu päivitystoiminnolle välitettyjen viestien kautta, Elm-ohjelman koko virta voidaan esittää sarjana mallimuutoksia. Debuggerille Elm on kuin vuoropohjainen strategiapeli. Tämän avulla virheenkorjaaja voi suorittaa todella upeita tekoja, kuten matkustaa ajan myötä. Se voi liikkua edestakaisin ohjelmassa läpi siirtymällä eri mallimuutosten välillä, jotka tapahtuivat ohjelman elinkaaren aikana.
Voit oppia lisää virheenkorjauksesta tässä .
Joten sanotte, että olemme rakentaneet mukavan lelun, mutta voiko Hammasta käyttää johonkin vakavaan? Ehdottomasti.
Yhdistetään ostoskorin käyttöliittymä asynkroniseen käyttöliittymään. Jotta se olisi mielenkiintoinen, toteutamme jotain erityistä. Oletetaan, että haluamme tarkastaa kaikki kärryt ja niiden sisällön reaaliajassa. Todellisessa elämässä voisimme käyttää tätä lähestymistapaa tuodaksemme ylimääräisiä markkinointi- / myyntimahdollisuuksia verkkokauppaan tai markkinapaikkaan, tai tehdä joitakin ehdotuksia käyttäjälle tai arvioida tarvittavat varastoresurssit ja paljon muuta.
Joten varastamme ostoskorin asiakaspuolelle ja ilmoitamme palvelimelle myös jokaisesta ostoskorista reaaliajassa.
Jotta asiat pysyisivät yksinkertaisina, toteutamme taustamme käyttämällä Pythonia. Löydät taustakoodin koko koodin tässä .
Se on yksinkertainen verkkopalvelin, joka käyttää WebSocketia ja seuraa ostoskorin sisältöä muistissa. Yksinkertaisuuden vuoksi renderöimme kaikkien muiden ostoskorin samalla sivulla. Tämä voidaan helposti toteuttaa erillisellä sivulla tai jopa erillisenä Elm-ohjelmana. Toistaiseksi jokainen käyttäjä voi nähdä yhteenvedon muiden käyttäjien ostoskorista.
Kun käyttöliittymä on paikallaan, meidän on nyt päivitettävä Elm-sovelluksemme lähettääksesi ja vastaanottaaksesi ostoskoripäivityksiä palvelimelle. Käytämme JSONia koodaamaan hyötykuormamme, jota Elmillä on erinomainen tuki.
Toteutamme kooderin muuntamaan Elm-tietomallimme JSON-merkkijonoesitykseksi. Tätä varten meidän on käytettävä Json. Koodaa kirjasto .
module CartEncoder exposing (cart) import Cart2 exposing (Cart, Item, Product) import List exposing (map) import Json.Encode exposing (..) product : Product -> Value product product = object [ ('name', string product.name) , ('price', float product.price) ] item : Item -> Value item item = object [ ('product', product item.product) , ('qty', int item.qty) ] cart : Cart -> Value cart cart = list (map item cart)
Kirjasto tarjoaa joitain toimintoja (kuten string
, int
, float
, object
jne.), Jotka ottavat Elm-objektit ja tekevät niistä JSON-koodatut merkkijonot.
Dekooderin käyttöönotto on hieman hankalampi, koska kaikilla Elm-tiedoilla on tyyppejä, ja meidän on määriteltävä, mikä JSON-arvo on muunnettava mihin tyyppiin:
module CartDecoder exposing (cart) import Cart2 exposing (Cart, Item, Product) -- decoding for Cart import Json.Decode exposing (..) -- will decode cart from string cart : Decoder (Cart) cart = list item -- decoder for cart is a list of items item : Decoder (Item) item = object2 Item -- decoder for item is an object with two properties: ('product' := product) -- 1) 'product' of product ('qty' := int) -- 2) 'qty' of int product : Decoder (Product) product = object2 Product -- decoder for product also an object with two properties: ('name' := string) -- 1) 'name' ('price' := float) -- 2) 'price'
Koska lopullinen Elm-koodi on vähän pidempi, löydät sen tässä . Tässä on yhteenveto käyttöliittymäsovellukseen tehdyistä muutoksista:
Olemme käärineet alkuperäisen update
toiminto toiminnolla, joka lähettää muutoksia ostoskorin sisältöön taustapuolelle joka kerta kun ostoskoria päivitetään:
updateOnServer msg model = let (newModel, have_to_send) = update msg model in case have_to_send of True -> -- send updated cart to server (!) newModel [ WebSocket.send server (encode 0 (CartEncoder.cart newModel.cart)) ] False -> -- do nothing (newModel, Cmd.none)
Olemme myös lisänneet ylimääräisen viestityypin ConsumerCarts String
saada päivityksiä palvelimelta ja päivittää paikallinen malli vastaavasti.
Näkymä on päivitetty muokkaamaan muiden kärryjen yhteenveto consumersCartsView
-painikkeella toiminto.
WebSocket-yhteys on muodostettu tilaamaan taustakuva kuuntelemaan muiden kärryjen muutoksia.
subscriptions : Model -> Sub Msg subscriptions model = WebSocket.listen server ConsumerCarts server = 'ws://127.0.0.1:8765'
Olemme myös päivittäneet päätoimintomme. Käytämme nyt Html.program
ylimääräisellä init
ja subscriptions
parametrit. init
määrittää ohjelman alkuperäisen mallin ja subscription
määrittää luettelon tilauksista.
Tilaus on tapa, jolla voimme käskeä Elmiä kuuntelemaan muutoksia tietyillä kanavilla ja välittämään nämä viestit update
toiminto.
main = Html.program { init = init , view = view , update = updateOnServer , subscriptions = subscriptions } init = ( Model [] -- empty cart [ Product 'Bicycle' 100.50 -- stock , Product 'Rocket' 15.36 , Product 'Bisquit' 21.15 ] Nothing -- error (no error at beginning) [] -- consumer carts list is empty , Cmd.none)
Lopuksi olemme käsitelleet tapaa, jolla puramme ConsumerCarts-viestin, jonka saamme palvelimelta. Tämä varmistaa, että ulkoisesta lähteestä saamamme tiedot eivät riko sovellusta.
ConsumerCarts message -> case decodeString (Json.Decode.list CartDecoder.cart) message of Ok carts -> ( consumer_carts = carts , False) Err msg -> ( model , False)
Elm on erilainen. Se vaatii kehittäjää ajattelemaan toisin.
Jokainen, joka tulee JavaScriptiä ja vastaavia kieliä edustavalle alueelle, yrittää oppia Elmin tapaa tehdä asioita.
Viime kädessä Elm tarjoaa kuitenkin jotain, mitä muut kehykset - jopa suosituimmat - usein taistelevat. Nimittäin se tarjoaa keinon rakentaa vankkoja käyttöliittymäsovelluksia sotkeutumatta valtavaan yksityiskohtaiseen koodiin.
Elm myös abstraktio monista JavaScriptin aiheuttamia vaikeuksia yhdistämällä älykäs kääntäjä tehokkaaseen virheenkorjaimeen.
Elm on sitä mitä etupään kehittäjät ovat kaipanneet niin kauan. Nyt kun olet nähnyt sen toiminnassa, ota se itse pyörimään ja nauti eduista rakentamalla seuraava web-projekti kaupungissa Elm.