I have a dropdown which shows text as moredetails with a keyboard-down-arrow, on clicking it expands and i can see the required fields. What i am trying to achieve is once on clicking the button when the secondary field expands i want to change the text to 'less details', i am able to achieve till like on expansion the keyboard downarrow mark becomes keyboard up arrow mark.
this is my code
Html.span
[ Attributes.class "details" ]
[ Html.a
[ Attributes.href "#", Events.onClick (ExpandDetails tx.id)]
[ Html.text "More detail"
, Html.i
[ Attributes.class "material-icons" ]
[ if expanded then
Html.text "keyboard_arrow_up"
else
Html.text "keyboard_arrow_down"
]
]
]
i am able to make it till if expands show downarrow but along with it i need text to change from more details to less details and on clicking less details it should be back to more details.
If I'm understanding correctly, you could define both the button and text in a let expression before the dropdown code. Something like:
let
( dropdownButton, dropdownText ) =
if expanded then
( "keyboard_arrow_up", "Less details" )
else
( "keyboard_arrow_down", "More details" )
in
Html.span [ Attributes.class "details" ]
[ Html.a
[ Attributes.href "#"
, Events.onClick (ExpandDetails tx.id)
]
[ Html.text dropdownText
, Html.i [ Attributes.class "material-icons" ]
[ Html.text dropdownButton ]
]
]
Here's an alternative.
Move the link into a function that takes the Strings as arguments.
viewDetails : Tx -> Bool -> Html Msg
viewDetails tx expanded =
let
lessOrMoreLink =
if expanded then
viewExpandLink "Less" "keyboard_arrow_up"
else
viewExpandLink "More" "keyboard_arrow_down"
in
Html.span
[ Attributes.class "details" ]
[ lessOrMoreLink tx.id ]
viewExpandLink : String -> String -> Int -> Html Msg
viewExpandLink txt arrow id =
Html.a
[ Attributes.href "#"
, Events.onClick (ExpandDetails id)
]
[ Html.text (txt ++ " details")
, Html.i
[ Attributes.class "material-icons" ]
[ Html.text arrow ]
]
Related
I am extremely new to Elm, and I am encountering a problem which frustrates me to no end.
Here is my code:
view : Model -> Html Msg
view model =
img [src "Img1.png", width 300, height 300] []
div []
[ input [ onInput ChangeUserInput ] []
, button [ onClick SaveText ] [ text "Save" ]
, button [ onClick Clear ] [ text "Clear" ]
, h1 [] [text model.userInput]
]
And the error I receive is that
The `img` function expects 2 arguments, but it got 5 instead
I think its parsing the div tag arguments as img arguments, but I can't figure out how to fix it.
Your view function needs to return a single HTML element. At the moment it seems you are trying to return two elements: an img and a div. The div and its two arguments are being picked up as arguments to the img because there is nothing in your code that Elm can use to identify the end of the list of arguments to pass to the img function.
You will need to wrap them both in an element that contains them, for example, another div:
view : Model -> Html Msg
view model =
div []
[ img [ src "Img1.png", width 300, height 300 ] []
, div []
[ input [ onInput ChangeUserInput ] []
, button [ onClick SaveText ] [ text "Save" ]
, button [ onClick Clear ] [ text "Clear" ]
, h1 [] [ text model.userInput ]
]
]
I have been trying several things and cannot work out how to style this Elm table with Bootstrap so it's striped. I am trying to use elm-bootstrap and have installed rundis/elm-bootstrap 4.1.0
Bootstrap.Table is currently unused:
module Players.List exposing (..)
import Html exposing (..)
import Html.Attributes exposing (class)
import Msgs exposing (Msg)
import Models exposing (Player)
import RemoteData exposing (WebData)
import Bootstrap.Table as Table
view : WebData (List Player) -> Html Msg
view response =
div []
[ nav
, maybeList response
]
nav : Html Msg
nav =
div [ class "clearfix mb2 white bg-black" ]
[ div [ class "left p2" ] [ text "Players" ] ]
maybeList : WebData (List Player) -> Html Msg
maybeList response =
case response of
RemoteData.NotAsked ->
text ""
RemoteData.Loading ->
text "Loading..."
RemoteData.Success players ->
list players
RemoteData.Failure error ->
text (toString error)
list : List Player -> Html Msg
list players =
div [ class "col-md-4" ]
[ table [ class "table table-striped" ]
[ thead []
[ tr []
[ th [] [ text "Id" ]
, th [] [ text "Initials" ]
, th [] [ text "Time" ]
, th [] [ text "Score" ]
]
]
, tbody [] (List.map playerRow players)
]
]
playerRow : Player -> Html Msg
playerRow player =
tr []
[ td [] [ text player.id ]
, td [] [ text player.initials ]
, td [] [ text (toString player.time) ]
, td [] [ text (toString player.score) ]
]
As this should be ultra simple I'm clearly missing something here. How can I make this table striped?
Your example uses HTML functions from Elm's HTML library but you're probably going to have a better time using the appropriate Bootstrap types and functions. For example, using the table options defined in the documentation, you could rewrite the view functions like this:
list : List Player -> Html msg
list players =
Table.table
{ options = [ Table.striped ]
, thead = Table.thead []
[ Table.tr []
[ Table.th [] [ text "Id" ]
, Table.th [] [ text "Initials" ]
, Table.th [] [ text "Time" ]
, Table.th [] [ text "Score" ]
]
]
, tbody = Table.tbody [] (List.map playerRow players)
}
playerRow : Player -> Table.Row msg
playerRow player =
Table.tr []
[ Table.td [] [ text player.id ]
, Table.td [] [ text player.initials ]
, Table.td [] [ text (Debug.toString player.time) ]
, Table.td [] [ text (Debug.toString player.score) ]
]
That will give you the right HTML but you may still need to import the Bootstrap styles. The documentation gives an example of including the stylesheet, which you could do in some wrapping function, for example:
import Bootstrap.Grid as Grid
import Bootstrap.Table as Table
import Bootstrap.CDN as CDN
view : Model -> Html Msg
view model =
Grid.container []
[ CDN.stylesheet -- creates an inline style node with the Bootstrap CSS
, Grid.row []
[ Grid.col []
[ list model.players ]
]
]
Here is a slimmed down Ellie example to play with.
Can someone tell me why the following code is not working? It is supposed to set the date in a field when it loads, then allow the date to be changed by clicking on the field. I'm using rebol/view 2.7.8 on linux. Actually, I think this code used to work years ago when I was using MS Windows, but not under linux for some reason.
drl
rebol []
trace true
out: layout [
style dater txt bold right [trans-date/date: copy (form now/date)] 48x24
dater "T-Date:" trans-date: field 80x24 (form now/date) feel [
engage: func [face action event][
if action = 'up [
lv-dat: request-date/date/offset (now/date) 450x375
if lv-dat <> none [
trans-date/text: form lv-dat
show trans-date
]
]
]
show trans-date
]
]
view out
Here is a cleaned up version of your code:
Rebol []
out: layout compose/deep [
style dater txt bold right 48x24
dater "T-Date:"
trans-date: field 80x24 (form now/date) feel [
engage: func [face action event][
if action = 'up [
lv-dat: request-date/date/offset (now/date) 450x375
if lv-dat [
face/text: form lv-dat
show face
]
]
]
]
]
view out
The main issue was the missing compose/deep call to evaluate the paren expressions before layout is called. However, that approach is not the usual way to initialize face properties, you should rather put init code in a do section of the VID block, like this:
Rebol []
out: layout [
style dater txt bold right 48x24
dater "T-Date:"
trans-date: field 80x24 feel [
engage: func [face action event][
if action = 'up [
lv-dat: request-date/date/offset now/date 450x375
if lv-dat [
face/text: form lv-dat
show face
]
]
]
]
do [trans-date/text: form now/date]
]
view out
Hope this helps.
A simple example:
If I type #"w" in style "area" how do I get an #"z"? (ex. "qwerty ww" -> "qzerty zz")
As you want the conversion on the fly, you can either modify R3-GUI before loading. So load r3-gui.r3 down to your local directory. Then you add the line if key == #"w" [key: #"z"] to the function do-text-key, so it looks like
do-text-key: funct [
"Process text face keyboard events."
face [object!]
event [event! object!]
key
] [
text-key-map/face: face
text-key-map/shift?: find event/flags 'shift
if no-edit: not tag-face? face 'edit [
key: any [select/skip text-key-map/no-edit key 2 key]
]
either char? key [
if key == #"w" [key: #"z"]
text-key-map/key: key
switch/default key bind text-key-map/chars 'event [
unless no-edit [
insert-text-face face key
]
]
] [
if find event/flags 'control [
key: any [select text-key-map/control key key]
]
text-key-map/key: key
switch/default key text-key-map/words [return event]
]
none
]
Probably the official way would be to use on-key wih Rebol3
load-gui
view [
a: area on-key [ ; arg: event
if arg/type = 'key [
if arg/key == #"w" [arg/key: #"z"]
]
do-actor/style face 'on-key arg face/style
]
]
And finally a way to do this with Rebol2 on the fly
key-event: func [face event] [
if event/type = 'key [
if all [event/key = #"w" ] [
append a/text #"z"
focus a
view w
return false
]
]
event
]
insert-event-func :key-event
view w: layout [
a: area
]
After reading some files of r3-gui (text-caret.r3, text-cursor.r3, text-edit.r3, text-keys.r3, text.r3) and the editor, I found a solution that allows me to insert not only a character but also string:
do %r3-gui.r3
insertText-moveCursor-updateFace: func [
face
string
n-move
][
insert-text-face face string
move-cursor face 'left n-move false
update-text-caret face
see-caret face
show-later face
]
i-m-u: :insertText-moveCursor-updateFace
view [
area on-key [
either arg/type = 'key [
switch/default arg/key [
#"w" [i-m-u face/names/text-box "z" 0]
#"[" [i-m-u face/names/text-box "[]" 1]
#"$" [i-m-u face/names/text-box "func [] []" 4]
] [
;switch/default
do-actor/style face 'on-key arg face/style
]
] [
;arg/type != 'key
do-actor/style face 'on-key arg face/style
]
]
]
Area is a compound styles. It is composed of a text-box and a scroller. They are contained in face/names.
I'm trying to add a field to a layout after it has been viewed
view/no-wait m: [field "hello"]
insert tail m 'field
insert tail m "hello"
update-face m
** Script error: update-face does not allow block! for its face argument
I want to update the whole layout, not just the field or some part of it. If I try to use
view m, it opens a new window. Do I just have to un-view it and then view again?
You can use the LAYOUT function in R3-GUI as well. See the example below:
view/no-wait m: layout [field "hello"]
;We need to get the BACKDROP container which is first sub-face in the WINDOW face
m: first faces? m
append-content m [
field "world"
]
do-events
Ofcourse there are also other ways how to handle layout content dynamically.
Try this example from Richard
REBOL [
Title: "Layouts example #20"
Author: "Richard Smolak"
Version: "$Id: layouts-20.r3 852 2010-10-07 13:28:26Z cyphre $"
]
stylize [
tbox: hpanel [
about: "Simple rectangular box."
facets: [
init-hint: 200x200
min-hint: 0x0
max-hint: guie/max-pair
break-after: 1
]
options: [
init-hint: [pair!]
]
actors: [
on-make: [
append face/options [
content: [
button "hello" on-action [print "hello"]
button "world" on-action [print "hello"]
]
]
do-actor/style face 'on-make none 'hpanel
]
]
draw: [
pen red
fill-pen blue
box 0x0 (viewport-box/bottom-right - 1)
]
]
]
view [
test: tbox
button "clear"
on-action [
clear-content test
]
button "set"
on-action [
set-content test [
button "test"
field "the best"
]
]
button "insert"
on-action [
insert-content test bind/set probe reduce [to-set-word copy/part random "abcdefgh" 2 'button join "button #" 1 + length? test/gob] 'system
]
button "append"
on-action [
append-content test reduce ['button join "button #" 1 + length? test/gob]
]
button "remove 2 faces at pos 3"
on-action [
remove-content/pos/part test 3 2
]
]
so the words you're looking for are append-content and insert-content which take a face and a block as parameters where the block contains the definition of another face.
I don't know view yet, but I have a hint. The first line sets "m" to the block [field "hello"]. Check to see what "update-face" expects...