I want to clear the text field and want to create a new placeholder when pressing a button. Additionally I want an Increment in the placeholder that counts every new text field that is created (player 1, player 2, player 3, etc.) I tried to use the Increment button from the elm docs. But I get an error:
Something is off with the 5th branch of this `case` expression:
78| model "Player" + 1
^^^^^^^^^^^^^^^^^^
The 5th branch is:
number
But the type annotation on `update` says it should be:
Model
I tried to create a new string player that adds every time the "+add" button is pressed +1. So with an onClick event + the name(Clear), how it is also done in the docs.
Here is my Elm Code:
--imports
...
-- MAIN
main =
Browser.sandbox { init = init, update = update, view = view }
-- MODEL
type alias Player =
{ player : String
, strength : Int
, number : Int
}
type alias Model =
{ content : String
, teams : List Player
, currentNumber : Int
, currentPlayer : String
, currentStrength : Int
}
init : Model
init =
{ content = ""
, teams = []
, currentNumber = 0
, currentPlayer = ""
, currentStrength = 0
}
-- UPDATE
type Msg
= Change String
| Clear
update : Msg -> Model -> Model
update msg model =
case msg of
Change newContent ->
{ model | content = newContent }
Clear ->
model "Player" + 1
-- VIEW
view : Model -> Html Msg
view model =
div []
[ h1 [style "font-family" "impact"] [ text "Team Creator" ]
, h2 [style "font-family" "impact"] [ text "Name and Strength:" ]
, div[] [ input [ placeholder "🏅 Player 1", style "width" "300px"] [] ]
, input [ placeholder "💪🏼 Strength", style "width" "300px"] []
, div [] [ button [ style "background-color" "#66cc81", style "color" "white", onClick Clear] [ text "+ADD" ] ]
, h2 [style "font-family" "impact"] [ text "Teams:" ]
, div [] [ text (model.currentPlayer)]
]
As the error message states, you are returning a type String from a function that returns Model by its type signature. The problem is this line
Clear ->
model "Player" + 1
It is a bit unclear what this is supposed to do, but in the case expression above, the code creates a new model where it makes the update content = newContent. If you want to update some other field in the model, you need a similar pattern. For example (not 100% sure about the syntax, but you'll hopefully get the idea)
Clear ->
{ model | currentNumber = currentNumber + 1 }
Related
I am trying to update my bitcoin price field in my List Token Model in my update function. This is my code I cannot seem to get it to only update the price field. Do I need to access the list elements seeing as my model is list? Is this possible to do using record syntax in elm?
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (..)
import Bass exposing (style, center, h1)
import Http
import Json.Decode as Decode
main =
Html.program
{ init = init
, view = view
, update = update
, subscriptions = subscriptions
}
------------- MODEL
type alias Model =
{ tokens : List Token
}
init : (Model, Cmd Msg)
init =
(initialModel , Cmd.none)
initialModel : Model
initialModel =
{ tokens = [Token "Bitcoin" "150" "11000.00"]
}
type alias Token =
{ name : String
, holdings : String
, price : String
}
------------- UPDATE
type Msg
= FetchDatabasePrice | FetchLivePrice (Result Http.Error String)
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
FetchDatabasePrice ->
(model, getPrice )
FetchLivePrice (Ok newPrice) ->
( { model | price = newPrice }, Cmd.none )
FetchLivePrice (Err _) ->
(model,Cmd.none)
getPrice : Cmd Msg
getPrice =
let
url = "https://api.coinmarketcap.com/v1/ticker/bitcoin/"
request = Http.get url decodedUrl
in
Http.send FetchLivePrice request
decodedUrl : Decode.Decoder String
decodedUrl = Decode.at ["price_usd"] Decode.string
------------- SUBSCRIPTIONS
subscriptions : Model -> Sub Msg
subscriptions model =
Sub.none
------------- VIEW
view : Model -> Html Msg
view model =
div []
[nav
, div [] [list model.tokens]
, div [] [ button [onClick (FetchDatabasePrice) ] [text "Fetch Price"] ]
]
------BROKEN INTO PIECES---------
nav : Html Msg
nav = div [Bass.style
[center
, Bass.h1
, [("background-color", "black")
, ("color", "white")
]
]
]
[ div [] [text "Crypto Nutshell"]]
list : List Token -> Html Msg
list tokens =
div [Bass.style
[Bass.left_align
]
]
[div [ class "p1"]
[ table []
[ thead []
[ tr []
[ th [] [text "Name"]
, th [] [text "Holdings"]
, th [] [text "Price"]
, th [] [text "Actions"]
]
]
, tbody [] (List.map tokenRow tokens)
]
]
]
tokenRow : Token -> Html Msg
tokenRow token =
tr []
[ td [] [ text token.name ]
, td [] [ text token.holdings ]
, td [] [ text token.price ]
]
This is my error:
-- TYPE MISMATCH ------------------------------------------------------ test.elm
The definition of `update` does not match its type annotation.
50| update : Msg -> Model -> (Model, Cmd Msg)
51| update msg model =
52|> case msg of
53|> FetchDatabasePrice ->
54|> (model, getPrice )
55|> FetchLivePrice (Ok newPrice) ->
56|> ( { model | price = newPrice }, Cmd.none )
57|> FetchLivePrice (Err _) ->
58|> (model,Cmd.none)
The type annotation for `update` says it always returns:
( Model, Cmd Msg )
But the returned value (shown above) is a:
( { b | price : String }, Cmd Msg )
Hint: The record fields do not match up. One has tokens. The other has price.
-- TYPE MISMATCH ------------------------------------------------------ test.elm
`model` is being used in an unexpected way.
56| ( { model | price = newPrice }, Cmd.none )
^^^^^
Based on its definition, `model` has this type:
Model
But you are trying to use it as:
{ b | price : a }
Hint: The record fields do not match up. One has tokens. The other has price.
The type errors are fundamentally telling you your issue - you are trying to work on a Token, but you don't have one - you have a Model.
How do we get from one to the other? Well. We start with a model, and we can do model.tokens to get a List Token. We then want to modify that list to contain the new tokens, updated. The normal way to do this is with List.map. This operates on each Token and gives us the updated list. Following these steps:
FetchLivePrice (Ok newPrice) ->
let
updatePrice = (\token -> { token | price = newPrice })
updated = List.map updatePrice model.tokens
in
({ model | tokens = updated }, Cmd.none )
Now, the solution I've given is a simple one that will fall apart when you have multiple different tokens (they will all get changed at the same time). As you only have one right now, the same thing could be achieved just by simplifying the model to take only a single token, not a list.
You will need to start identifying which token you are getting the price for so you can update the right one, if you want to be able to use the ability to have multiple tokens.
In reality, you probably want this to end up looking something like:
FetchLivePrice tokenId (Ok newPrice) ->
({ model | tokens = tokenUpdatePrice tokenId newPrice model.tokens, Cmd.none)
Where tokenUpdatePrice is a function that manipulates your list (or other data structure - a dictionary might be appropriate, although you might need to store a separate order for presentation) to update the appropriate records. tokenId will be something used to identify the token.
Consider the business process "Review and Approve (one or more reviewers) - Assign a review task to multiple reviewers".
When I choose reviewers I see only their properties cm:userName. How to display all the properties of the type cm:person?
For example:
cm:userName
cm:firstName
cm:middleName
cm:email
cm:organizationId
cm:jobtitle
cm:googleusername
And so on...
Instead of this container (part of the association.ftl):
...
<div id="${controlId}-currentValueDisplay" class="current-values"></div>
...
I would like to use table. IMHO for that I should override some parts of the
Alfresco.ObjectFinder, such as:
if (this.options.displayMode == "items")
{
Dom.get(this.id + "-currentValueDisplay").innerHTML = displayValue;
}
...etc. But how to display all the properties of the selected reviewers?
Let's say, this part:
displayValue +=
this.options.objectRenderer.renderItem(
item,
16,
"<div class='itemtype-" + $html(item.type) +
"' style='word-wrap: break-word;'>{icon} {name}</div>"
);
I assume that it's property is name
Ok, then where to find the mapping "property in object-finder : property in the person type"?
To display the companyname, email etc fields to you need to modify the following files in the repo side.
C:\Alfresco\tomcat\webapps\alfresco\WEB-INF\classes\alfresco\extension\templates\webscripts\org\alfresco\repository\forms\pickerresults.lib.js
C:\Alfresco\tomcat\webapps\alfresco\WEB-INF\classes\alfresco\extension\templates\webscripts\org\alfresco\repository\forms\pickerresults.lib.ftl
In the pickerresults.lib.js, I added the required extra properties in the CreatePersonResult(node) method.
function createPersonResult(node)
{
var personObject =
{
typeShort: node.typeShort,
isContainer: false,
properties: {},
displayPath: node.displayPath,
nodeRef: "" + node.nodeRef
}
// define properties for person
personObject.properties.userName = node.properties.userName;
personObject.properties.name = (node.properties.firstName ? node.properties.firstName + " " : "") +
(node.properties.lastName ? node.properties.lastName : "") +
" (" + node.properties.userName + ")";
personObject.properties.jobtitle = (node.properties.jobtitle ? node.properties.jobtitle : "");
//Add the extra properties here
personObject.properties.organization =(node.properties.organization ? node.properties.organization : "");
personObject.properties.googleusername =(node.properties.googleusername ? node.properties.googleusername : "");
return personObject;
}
In the pickerresults.lib.ftl, I added the extra properties to the result set, below to the "selectable" : ${row.selectable?string}</#if>
"nodeRef": "${row.item.nodeRef}"<#if row.selectable?exists>,
"selectable" : ${row.selectable?string}</#if>,
"company": "${row.item.properties.organization!""}",
"googleusername": "${row.item.properties.googleusername!""}",
"jobtitle": "${row.item.properties.jobtitle!""}"
Hope this helps you now.
Object-finder.js is used for different kind of objects like person, tags etc.
item.type is cm:person, but it doesn't have all the person of person object here. Refer the below image.
In Elm (0.18) I'm calling one http DELETE endpoint that if successful responds with 200 and an empty body.
In this case (of success) I need to pass back a message with the initial id (OnDelete playerId). But as the body is empty i can't parse it from there.
Currently I'm doing it like this, but is there a more elegant way to write the expect part of Http.Request:
Http.expectStringResponse (\response -> Ok playerId)
?
This reflects my current code:
deletePlayer : PlayerId -> Cmd Msg
deletePlayer playerId =
deleteRequest playerId
|> Http.send OnDelete
deleteRequest : PlayerId -> Http.Request PlayerId
deleteRequest playerId =
Http.request
{ body = Http.emptyBody
, expect = Http.expectStringResponse (\response -> Ok playerId)
, headers = []
, method = "DELETE"
, timeout = Nothing
, url = "http://someHost/players/" ++ playerId
, withCredentials = False
}
type alias PlayerId =
String
Elm v0.19 added expectWhatever. It behaves slightly different with the Result being checked for errors, but a similar effect.
I've created a helper expectUnit for "empty" 200 responses.
expectUnit : Expect ()
expectUnit =
Http.expectStringResponse << always <| Ok ()
deleteThing : String -> Request ()
deleteThing path =
Http.request
{ method = "DELETE"
, headers = []
, url = "http://localhost/api"
, body = Http.jsonBody <| Encode.object [ ( "path", Encode.string path ) ]
, expect = expectUnit
, timeout = Nothing
, withCredentials = False
}
But for you, the best you could get is.
{ ...
, expect = Http.expectStringResponse << always <| Ok playerId
...
}
Or you could create a helper (which is actually the singleton or pure for Expect)
alwaysExpect : a -> Expect a
alwaysExpect =
Http.expectStringResponse << always << Ok
Which could be used like
{ ...
, expect = alwaysExpect playerId
...
}
I am trying to understand how data binding works in Go walk.
I have reviewed the somewhat complex data binding example, but I am having difficulties implementing a simple, one field data binding.
The code below demonstrates more or less what I am trying to achieve - I want the text label to be bound to the message variable (i.e., to be synchronized with its content) - of course, without the need for me to push changes to the label itself.
package main
import (
"github.com/lxn/walk"
. "github.com/lxn/walk/declarative"
"strconv"
"time"
)
func main() {
var messageLabel *walk.Label
var message string = "Hello"
// Change `message` over 5 seconds
go func() {
for i := 1; i < 6; i++ {
time.Sleep(time.Second)
message = "Counting: " + strconv.Itoa(i)
// I want to make it work
// without this line below
messageLabel.SetText(message)
}
}()
// Build a simple window with a text label
// that is supposed to be bound to the
// contents of the `message` variable
MainWindow{
Title: "Binding Test",
MinSize: Size{300, 50},
Layout: VBox{},
Children: []Widget{
Label{
AssignTo: &messageLabel,
Text: message,
// Text: BindTo{message} // Objective
},
},
}.Run()
}
I didn't see any Databinder code in your snapshot.
In that exanple you mentioned,these code below makes databinding work
DataBinder: DataBinder{
AssignTo: &db,
Name: "animal",
DataSource: animal,
ErrorPresenter: ToolTipErrorPresenter{},
},
It binds the data who calls Bind("Name") to the field with the same name in Datasource which is animal in that example.
I'm trying to write a trait (in Scala 2.8) that can be mixed in to a case class, allowing its fields to be inspected at runtime, for a particular debugging purpose. I want to get them back in the order that they were declared in the source file, and I'd like to omit any other fields inside the case class. For example:
trait CaseClassReflector extends Product {
def getFields: List[(String, Any)] = {
var fieldValueToName: Map[Any, String] = Map()
for (field <- getClass.getDeclaredFields) {
field.setAccessible(true)
fieldValueToName += (field.get(this) -> field.getName)
}
productIterator.toList map { value => fieldValueToName(value) -> value }
}
}
case class Colour(red: Int, green: Int, blue: Int) extends CaseClassReflector {
val other: Int = 42
}
scala> val c = Colour(234, 123, 23)
c: Colour = Colour(234,123,23)
scala> val fields = c.getFields
fields: List[(String, Any)] = List((red,234), (green,123), (blue,23))
The above implementation is clearly flawed because it guesses the relationship between a field's position in the Product and its name by equality of the value on those field, so that the following, say, will not work:
Colour(0, 0, 0).getFields
Is there any way this can be implemented?
Look in trunk and you'll find this. Listen to the comment, this is not supported: but since I also needed those names...
/** private[scala] so nobody gets the idea this is a supported interface.
*/
private[scala] def caseParamNames(path: String): Option[List[String]] = {
val (outer, inner) = (path indexOf '$') match {
case -1 => (path, "")
case x => (path take x, path drop (x + 1))
}
for {
clazz <- getSystemLoader.tryToLoadClass[AnyRef](outer)
ssig <- ScalaSigParser.parse(clazz)
}
yield {
val f: PartialFunction[Symbol, List[String]] =
if (inner.isEmpty) {
case x: MethodSymbol if x.isCaseAccessor && (x.name endsWith " ") => List(x.name dropRight 1)
}
else {
case x: ClassSymbol if x.name == inner =>
val xs = x.children filter (child => child.isCaseAccessor && (child.name endsWith " "))
xs.toList map (_.name dropRight 1)
}
(ssig.symbols partialMap f).flatten toList
}
}
Here's a short and working version, based on the example above
trait CaseClassReflector extends Product {
def getFields = getClass.getDeclaredFields.map(field => {
field setAccessible true
field.getName -> field.get(this)
})
}
In every example I've seen the fields are in reverse order: the last item in the getFields array is the first one listed in the case class. If you use case classes "nicely", then you should just be able to map productElement(n) onto getDeclaredFields()( getDeclaredFields.length-n-1).
But this is rather dangerous, as I don't know of anything in the spec that insists that it must be that way, and if you override a val in the case class, it won't even appear in getDeclaredFields (it'll appear in the fields of that superclass).
You might change your code to assume things are this way, but check that the getter method with that name and the productIterator return the same value and throw an exception if they don't (which means that you don't actually know what corresponds to what).
You can also use the ProductCompletion from the interpreter package to get to attribute names and values of case classes:
import tools.nsc.interpreter.ProductCompletion
// get attribute names
new ProductCompletion(Colour(1, 2, 3)).caseNames
// returns: List(red, green, blue)
// get attribute values
new ProductCompletion(Colour(1, 2, 3)).caseFields
Edit: hints by roland and virtualeyes
It is necessary to include the scalap library which is part of the scala-lang collection.
Thanks for your hints, roland and virtualeyes.