很抱歉,由于英语不好,我可能无法清楚地解释我的问题。这次我抽象了这个问题并在一个反例中进行了演示。
有两个子模块(CounterPair
和CounterTriplet
),每个子模块都使用Counter
来显示num
的{{1}}个字段并显示某些内容else(本例中的其他SharedModel
)。我突出显示Counter
显示Counter
的{{1}}红色。
SharedModel
和num
的红色Counter
应该同步,因为它们代表相同的CounterPair
。此外,CounterTriple
的{{1}}字段也需要在任何红色SharedModel
更新时进行更新。下面显示的代码只是设法显示我想要的东西,但缺少更新链。我该如何实施更新链?
您可以在Try Elm
上试用此代码。
shared
我正在使用Model
,视图层次结构就像
Counter
import Html exposing (div, button, text)
import Html.App as App exposing (beginnerProgram)
import Html.Events exposing (onClick)
import Html.Attributes exposing (style)
main =
beginnerProgram { model = init, view = view, update = update }
-------------------------------------
type alias SharedModel =
{ num : Int
, foo : String
}
sharedInit =
SharedModel 0 "Foo"
--------------------------------------
type alias Model =
{ shared : SharedModel
, pair : CounterPair
, triplet : CounterTriplet
}
init =
let
shared = sharedInit
in
Model shared (pairInit shared) (tripletInit shared)
view model =
div []
[ App.map Pair (pairView model.pair)
, App.map Triplet (tripletView model.triplet)
]
type Msg
= Pair PairMsg
| Triplet TripletMsg
update msg model =
case msg of
Pair sub ->
let
pair = pairUpdate sub model.pair
in
{ model | pair = pair }
Triplet sub ->
let
triplet = tripletUpdate sub model.triplet
in
{ model | triplet = triplet }
----------------------------------------
type alias CounterTriplet =
{ localFst : CounterModel
, localSnd : CounterModel
, global : CounterModel
}
tripletInit shared =
CounterTriplet (counterInit 0) (counterInit 0) (counterInit shared.num)
tripletView model =
div [ style [("background-color","lightgray"), ("margin-bottom", "1rem")] ]
[ App.map TriLocalSnd (counterView "green" model.localFst)
, App.map TriLocalSnd (counterView "green" model.localSnd)
, App.map TriGlobal (counterView "red" model.global)
]
type TripletMsg
= TriLocalFst CounterMsg
| TriLocalSnd CounterMsg
| TriGlobal CounterMsg
tripletUpdate msg model =
case msg of
TriLocalFst sub ->
let
localFst = counterUpdate sub model.localFst
in
{ model | localFst = localFst }
TriLocalSnd sub ->
let
localSnd = counterUpdate sub model.localSnd
in
{ model | localSnd = localSnd }
TriGlobal sub ->
let
global = counterUpdate sub model.global
in
{ model | global = global }
----------------------------------------------
type alias CounterPair =
{ local : CounterModel
, global : CounterModel
}
pairInit shared =
CounterPair (counterInit 0) (counterInit shared.num)
pairView model =
div [ style [("background-color","lightgray"), ("margin-bottom", "1rem")] ]
[ App.map PairLocal (counterView "green" model.local)
, App.map PairGlobal (counterView "red" model.global)
]
type PairMsg
= PairLocal CounterMsg
| PairGlobal CounterMsg
pairUpdate msg model =
case msg of
PairLocal sub ->
let
local = counterUpdate sub model.local
in
{ model | local = local }
PairGlobal sub ->
let
global = counterUpdate sub model.global
in
{ model | global = global }
---------------------------------------
type alias CounterModel =
{ num : Int
, btnClicks : Int
}
counterInit num =
CounterModel num 0
counterView color model =
div [ style [("display","inline-block"), ("margin-right", "1rem")] ]
[ button [ onClick Decrement ] [ text "-" ]
, div [ style [("color", color)]] [ text (toString model.num) ]
, button [ onClick Increment ] [ text "+" ]
, div [ ] [ text ("btn click: " ++ (toString model.btnClicks)) ]
]
type CounterMsg = Increment | Decrement
counterUpdate msg model =
case msg of
Increment ->
{ model | num = model.num + 1, btnClicks = model.btnClicks + 1 }
Decrement ->
{ model | num = model.num - 1, btnClicks = model.btnClicks + 1 }
是自定义The Elm Architecture
,双击时可以变为,--------------------------------------------------------------------.
| View |
| ,------------------. ,------------------------------------------. |
| | SubView1 | | SubView2 | |
| | ,--------------. | | ,---------------. ,--------------------. | |
| | | Label(title) | | | | Label(title) | | Label(description) | | |
| | `--------------' | | `---------------' `--------------------' | |
| `------------------' `------------------------------------------' |
`--------------------------------------------------------------------'
字段。所以它是可编辑的。
Label
如下所示。问题是我想在编辑子子标签的值时更新<label>
的{{1}}。当我更新subview1的标题标签时,也应该更新subview2的标题标签,因为它们应该“共享”相同的<input>
但Model
的{{1}}在某种程度上是独立的,因此我需要将content
的更改一直转移到ViewModel
。我不认为这是实现我想要的实用方法,因为视图层次结构可能变得更加复杂。此外,几乎所有Content
都有特定的内容(value
,LabelModel
,value
等用于存储状态),因此需要对其进行初始化。因此,使ViewModel
整洁,例如Model
是不切实际的,因为我不知道Foo
和Bar
和BarBar
的归档位置ViewModel
和type alias ViewModel = Content
}}
Bar
我对榆树很新,所以这个问题可能看起来很愚蠢,对不起。
感谢您阅读(并回答:))
答案 0 :(得分:0)
当单个数据仅在一个位置表示时,Elm组件层次结构最有效。如果需要多个组件中的数据,则将其放在这些组件的最近共同祖先处。
在具体案例中,如果SubViewModel1.label.value
和SubViewModel2.titleLabel.value
实际上是同一条数据,那么它应该位于ViewModel
。
一旦数据存在于该位置,您就可以通过update
组件的ViewModel
函数与Msg
SubViewModel1
或...2
的{{1}}作出反应来对其中的更新作出反应,或者module View
import SubView1
import SubView2
type alias ViewModel =
{ content : Content
, subView1 : SubView1.Model
, subView2 : SubView2.Model
, label : String -- New!
}
type Msg
= SubView1Msg SubView1.Msg
| SubView2Msg SubView2.Msg
| ...
update action model =
case action of
...
(SubView1.UpdateLabel str) as action' ->
let
(subView1', fx) =
SubView1.update action' model.subView1
in
( { model
| subView1 = subView1'
, label = str
}
, Cmd.map SubView1Action fx
)
。像这样:
datarow