{"id":21647895,"url":"https://github.com/markknol/coconut.questions","last_synced_at":"2025-03-20T01:54:39.366Z","repository":{"id":69819640,"uuid":"196214461","full_name":"markknol/coconut.questions","owner":"markknol","description":"coconut.ui questions / answers","archived":false,"fork":false,"pushed_at":"2021-01-26T10:23:56.000Z","size":25,"stargazers_count":9,"open_issues_count":0,"forks_count":0,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-01-25T05:11:29.102Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/markknol.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-07-10T13:53:26.000Z","updated_at":"2021-01-26T10:23:58.000Z","dependencies_parsed_at":null,"dependency_job_id":"c9b7aaa6-d55a-47da-bb72-66e4e9017d45","html_url":"https://github.com/markknol/coconut.questions","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markknol%2Fcoconut.questions","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markknol%2Fcoconut.questions/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markknol%2Fcoconut.questions/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markknol%2Fcoconut.questions/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/markknol","download_url":"https://codeload.github.com/markknol/coconut.questions/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244536441,"owners_count":20468349,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-25T06:52:12.572Z","updated_at":"2025-03-20T01:54:39.347Z","avatar_url":"https://github.com/markknol.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Haxe Coconut.ui questions\n\n\u003e Questions / answers about [coconut.ui](https://github.com/MVCoconut/).\n\n--- \n\n## How to set attributes based on a condition\n\n\u003cdetails open\u003e\u003csummary\u003e\u003cb\u003eQuestion\u003c/b\u003e\u003c/summary\u003e\n\nThis doesn't seem to work: `\u003cspan class=\"\u003cif {true}\u003eactive\u003c/if\u003e\"\u003e`\n\n\u003c/details\u003e\n\n\u003cdetails open\u003e\u003csummary\u003e\u003cb\u003eAnswer\u003c/b\u003e\u003c/summary\u003e\n\nFor css classes, I suggest\n* `\u003cspan class={[\"item\" =\u003e true, \"active\" =\u003e isActive]}` \n* or `\u003cspan class={{ item: true, active: isActive}}`\n\nBut better yet,  \n```haxe\nstatic var ITEM:tink.domspec.ClassName = \"item\"; \nstatic var ACTIVE:tink.domspec.ClassName = \"active\" \n```\nAnd use it like  `\u003cspan class={ITEM.add([ACTIVE =\u003e isActive]}`.  \nIt's using this abstract: \u003chttps://github.com/haxetink/tink_domspec/blob/master/src/tink/domspec/ClassName.hx\u003e\n \n\u003c/details\u003e\n\n\n## How do you declare some var inside a render function?\n\n\u003cdetails open\u003e\u003csummary\u003e\u003cb\u003eAnswer\u003c/b\u003e\u003c/summary\u003e\n\n* One option is `function render() { var x = 123; return @hxx'\u003cspan\u003e{x}\u003c/span\u003e';  }`\n* Or you use `\u003clet\u003e`: \u003chttps://github.com/haxetink/tink_hxx/#let\u003e\n\n\u003c/details\u003e\n\n## Why doesn't float translate to a renderable\n\n\u003cdetails open\u003e\u003csummary\u003e\u003cb\u003eQuestion\u003c/b\u003e\u003c/summary\u003e\n \nI get error `Float should be coconut.ui.RenderResult`\n\n\u003c/details\u003e\n\n\u003cdetails open\u003e\u003csummary\u003e\u003cb\u003eAnswer\u003c/b\u003e\u003c/summary\u003e\n\nThat's on purpose, because e.g. in Spanish `1.234` means `1234`. In general you don't want `1.40632469e12` to be shown to user, so developers are forced to write their own float to string functions.\n\n\u003c/details\u003e\n\n## How to render an empty fragment\n\n\u003cdetails open\u003e\u003csummary\u003e\u003cb\u003eAnwer\u003c/b\u003e\u003c/summary\u003e\n\n- Use `\u003c\u003e\u003c/\u003e` for an empty fragment\n- If it's an `\u003cif\u003e\u003c/if\u003e`, it is fine to not have an `\u003celse\u003e` branch\n\n\u003c/details\u003e\n\n## How to pass a class in custom render function?\n\n\u003cdetails open\u003e\u003csummary\u003e\u003cb\u003eQuestion\u003c/b\u003e\u003c/summary\u003e\n \nLet's say I have `\u003ccustom class=${{\"active\": true}}\u003ew00t\u003c/custom\u003e`  \nAnd this render runction: `function custom(attr:{class:String}) '\u003cdiv class=${attr.class}\u003e\u003c/div\u003e'`  \nHow do you define `attr.class`? \n\n\u003c/details\u003e\n\n\u003cdetails open\u003e\u003csummary\u003e\u003cb\u003eAnswer\u003c/b\u003e\u003c/summary\u003e\n\n* Rename the attribute `class` to `className` and use `className:tink.domspec.ClassName`\n* More info: \u003chttps://github.com/haxetink/tink_domspec/blob/master/src/tink/domspec/ClassName.hx\u003e\n\n\u003c/details\u003e\n\n## How to use an optional callback? \n\n\n\u003cdetails open\u003e\u003csummary\u003e\u003cb\u003eQuestion\u003c/b\u003e\u003c/summary\u003e\n\nI have `@:attribute function handleClose():Void;`\n\n\u003c/details\u003e\n\n\u003cdetails open\u003e\u003csummary\u003e\u003cb\u003eAnswer\u003c/b\u003e\u003c/summary\u003e\n\nGive it a body, that'll be the default behavior so it's always safe to call.\n\n```haxe\n@:attribute function handleClose():Void {};\n```\n\nAs alternative, you can use otherwise (that'll allow it to actually be nullable)\n\n```haxe\n@:attribute var handeClose:()-\u003eVoid = null;\n```\n\n\u003c/details\u003e\n\n\n\n## How to access children within custom render function?\n\n\u003cdetails open\u003e\u003csummary\u003e\u003cb\u003eQuestion\u003c/b\u003e\u003c/summary\u003e\n\nIf you have `\u003ccustom\u003eWow\u003c/custom\u003e` which is a render function defined like this `function custom(attr:{})`, is it possible to get/render its children too?\n\n\u003c/details\u003e\n\n\u003cdetails open\u003e\u003csummary\u003e\u003cb\u003eAnswer\u003c/b\u003e\u003c/summary\u003e\n\nYep, this is as simple as:\n \n```haxe\nfunction custom(attr:{children:coconut.ui.Children}) '\u003cdiv class=\"custom\"\u003e${...attr.children}\u003c/div\u003e';\n```\n\n* You can pass children as second argument as well\n* The rules are a bit complex, to allow for different styles: \u003chttps://github.com/haxetink/tink_hxx/#tag-semantics\u003e\n\n\u003c/details\u003e\n\n## How to update page title with a component?\n\n\u003cdetails open\u003e\u003csummary\u003e\u003cb\u003eAnswer\u003c/b\u003e\u003c/summary\u003e\n\n```haxe\nimport js.Browser.document;\n\nclass PageInfo extends coconut.ui.View {\n  @:tracked @:attribute var title:String;\n  @:tracked @:attribute var description:String;\n\n  function render() return null;\n\n  function viewDidRender(_) {\n    document.title = title;\n    for (e in document.querySelectorAll('title'))\n      e.textContent = title;\n    for (e in document.querySelectorAll('meta[name=\"description]'))\n      (cast e:js.html.Element).setAttribute(\"content\", description);\n  }\n}\n```\n\nThis works as simple as `\u003cPageInfo title=\"${title} - ${pageName}\" description=\"${description}\"/\u003e`. It updates nicely when the values change :smiley:\n\nThat said, if you have the data in a model, you should rather apply it to the document via binding: `pageInfo.observables.title.bind(t -\u003e document.title = t)`.\n\n\u003c/details\u003e\n\n## Can I change styles in `RenderResult`?\n\n\u003cdetails open\u003e\u003csummary\u003e\u003cb\u003eAnswer\u003c/b\u003e\u003c/summary\u003e\n\nGenerally you can't modify `RenderResult` because it is a implementation detail and should not be touched. Instead (if you want to change font-size for example) you should pass the styles with a function like this:\n\n```haxe\n@:attr var renderChildren:(fontSize:Int)-\u003ecoconut.ui.Children;\n\nfunction render() '\u003c\u003e{...renderChildren(10)}\u003c/\u003e';\n```\n\n\u003c/details\u003e\n\n## How to render an space without `\u0026nbsp;`?\n\n\u003cdetails open\u003e\u003csummary\u003e\u003cb\u003eQuestion\u003c/b\u003e\u003c/summary\u003e\nIn some cases you want to render actual spaces and avoid non-breaking spaces. How to render an space without \u003ccode\u003e\u0026amp;nbsp;\u003c/code\u003e?\n\u003c/details\u003e\n\n\u003cdetails open\u003e\u003csummary\u003e\u003cb\u003eAnswer\u003c/b\u003e\u003c/summary\u003e\nUse \u003ccode\u003e${\" \"}\u003c/code\u003e\u003cbr/\u003e\u003cbr/\u003e\n \nIt dumps in a text node and after that the white space rules of the parent html element do their thing.\n\u003c/details\u003e\n \n## How to an approach inline scope inside a view?\n\n\u003cdetails open\u003e\u003csummary\u003e\u003cb\u003eQuestion\u003c/b\u003e\u003c/summary\u003e\n\nIs it possible to create/define a new observable scope within the view?  Something like this:\n```jsx\n\u003cfor {i in 0...10}\u003e\n \u003cscope enabled={false}\u003e\n    ${Std.string(enabled)}\n    \u003cbutton onclick=${enabled = true}\u003eenable\u003c/button\u003e\n    \u003cbutton onclick=${enabled = false}\u003edisable\u003c/button\u003e\n  \u003c/let\u003e\n\u003c/scope\u003e\n```\n\u003c/details\u003e\n\n\u003cdetails open\u003e\u003csummary\u003e\u003cb\u003eAnswer\u003c/b\u003e\u003c/summary\u003e\n  \nIt sorta depends on what you need, that thing will reset when the parent rerenders. You could try something like this:\n  \n```haxe\nclass Stateful\u003cT\u003e extends View {\n  @:attribute var init:Void-\u003eT;\n  @:attribute var content:{ final state:T; }-\u003eRenderResult;\n  var adhocState:T;\n  function render() {\n    if (adhocState == null) adhocState = init();\n    return content({ state: adhocState });\n  }\n}\n```\n\nThen use it like this:\n\n```jsx\n\u003cfor {i in 0...10}\u003e\n  \u003cStateful init={() -\u003e new SomeModel({ enabled: false })}\u003e\n     \u003ccontent\u003e\n       \u003cbutton onclick=${state.enabled = true}\u003eenable\u003c/button\u003e\n       \u003cbutton onclick=${state.enabled = false}\u003edisable\u003c/button\u003e\n     \u003c/content\u003e\n  \u003c/Stateful\u003e\n\u003c/for\u003e\n```\n\n\u003e Cool, how does `\u003ccontent\u003e` work here?\n\nChildless views have their child notes interpreted as attributes, a feature I termed [complex attributes](https://github.com/haxetink/tink_hxx/#complex-attributes)\n\n\u003c/details\u003e\n\n## How to pass non-observable array as attribute\n\n\u003cdetails open\u003e\u003csummary\u003e\u003cb\u003eQuestion\u003c/b\u003e\u003c/summary\u003e\n\nProblem: I don't want to convert to observable list, because it is just for some calculation. It's ok that the list doesn't update when an item is pushed to the array.  \nI get the error _\"`Array\u003cThing\u003e` is not observable, because `Array\u003cThing\u003e` is not observable because the field \\\"length\\\" is mutable\"_\n\n\u003c/details\u003e\n\n\u003cdetails open\u003e\u003csummary\u003e\u003cb\u003eAnswer\u003c/b\u003e\u003c/summary\u003e\n \n1. Use `@:skipCheck`\n   ```haxe\n   @:skipCheck @:attribute var plainArray:Array\u003cThing\u003e;\n   ```\n2. Use `@:pure`\n   ```haxe\n   @:pure typedef PureArray = Array\u003cThing\u003e;\n   ```\n3. or use `@:observable` instead of `@:pure` in example above\n\n\u003c/details\u003e\n\n## Are there coconut.ui components to handle routing ?\n\n\u003cdetails open\u003e\u003csummary\u003e\u003cb\u003eAnswer\u003c/b\u003e\u003c/summary\u003e\n\n1. If you want simple location hash and assuming the state is all in one place, then you could do something like `function viewDidMount() { window.onhashchange = function () {/* set states from hash here*/}; Observable.auto(() -\u003e /* compute url from states*/).bind(url -\u003e window.location.hash = url)}`. `Observable.auto` is what's underpinning every `@:computed` property\nand in essence a coconut view is something like `Observable.auto(this.render).bind(applyVDom)`.\n1. If you like a more elegant solution, check this out \u003chttps://github.com/kevinresol/coconut.router\u003e\n\n\u003c/details\u003e\n\n---\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarkknol%2Fcoconut.questions","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarkknol%2Fcoconut.questions","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarkknol%2Fcoconut.questions/lists"}