Nim and static type noob here. So the problem is when I compile my code and run 
it in browser, fill the name and description fields and click add thing button, 
my browser console gives following cryptic runtime errors:
    
    
      TypeError: c_225079 is null quicktest.js:579:16
        cstrToNimstr quicktest.js:579
        HEX24_10841036 quicktest.js:2878
        HEX3Aanonymous_10850242 quicktest.js:3172
        wrapper_10750162 quicktest.js:3049
        HEX3Aanonymous_10190109 quicktest.js:1234
    
    
    Run

I cannot interpret the error given, it seems that the error has something to do 
with the cstring -> string transformation. I've isolated the problem somewhat 
to the handler proc actionAddThing and the getVNodeById karax procedure. When I 
substitute the name and desc values into something more static eg. "foo" and 
"bar" the script works. (well of course I cannot capture user inputs but 
anyways...)

Here is the rather verbose code (sorry it's already pretty stripped version of 
the original code) with some commenting of my intents: 
    
    
    include karax/prelude
    
    # These are used in the html text input field's id:
    const
        IdInputThingName: kstring = "inputThingName"
        IdInputThingDesc: kstring = "inputThingDesc"
    
    
    type
        Thing = ref object
            uid: kstring
            name: kstring
            desc: kstring
    
    
    proc `$`(t: Thing): string =
        return "Thing(uid=" & $t.uid & ", name=" & $t.name & ", desc=" & 
$t.desc & ")"
    
    # Some getters for thing, after creating the thing, it's attributes 
shouldn't
    # be edited.
    proc getName*(thing: Thing): kstring =
        return thing.name
    
    
    proc getUid*(thing: Thing): kstring =
        return thing.uid
    
    
    proc getDesc*(thing: Thing): kstring =
        return thing.desc
    
    
    proc newThing(uid, name, desc: kstring): Thing =
        result = Thing(uid: uid, name: name, desc: desc)
    
    
    # proc which returns the thing factory with the id initialised to zero.
    # the returned closure factory will increment the id everytime the thing
    # is created and passes the uid to Thing constructor.
    proc thingBuilder(): proc(name, desc: kstring): Thing =
        var nextId = 0
        return proc (name, desc: kstring): Thing =
            nextId.inc()
            result = newThing("uid-" & $nextId, name, desc)
    
    # Creating the global factory:
    let thingFactory = thingBuilder()
    
    
    # App state and related procs/methods
    type
        AppState = ref object
            things: seq[Thing]
    
    
    proc newAppState(): AppState =
        # Default init is empty things list:
        result = AppState(things: @[])
    
    
    # Should modify the existing app state and it's
    # things list by adding the given thing into the list.
    proc addThing*(self: var AppState, t: Thing) =
        self.things.add(t)
    
    
    # Getter for the things list in app state.
    # Not sure if it's making copies or not?
    proc getAllThings*(self: AppState): seq[Thing] =
        result = @[]
        for t in self.things:
            result.add(t)
    
    
    # Handler for clicking the button. Should read the
    # text input field's (created in the makeControls proc) texts and create
    # the thing using the thingFactory. After this it should add the created
    # thing into the app state's thing list.
    proc actionAddThing(state: var AppState): proc() =
        return proc() =
            # These doesn't work, why?!
            let name = getVNodeById(IdInputThingName).value()
            let desc = getVNodeById(IdInputThingDesc).value()
            # If I substitute name and desc with "foo" and "bar"
            # this works. WTF!? Why I cannot get the values in those nodes?
            # let name = kstring("foo")
            # let desc = kstring("bar")
            
            # Create the thing based on the given name and desc:
            let thing = thingFactory(name, desc)
            
            echo("Thing created: ", $thing)
            # Add the created thing into app state's thing list:
            state.addThing(thing)
            echo $state.getAllThings()
    
    
    # Supposed to return odd string if the given number is
    # odd and even if even...duh. String is used when making
    # things and added into their class attribute.
    proc evenOdd(idx: int): kstring =
        if idx %% 2 != 0:
            return "even"
        return "odd"
    
    
    # Make/render the thing list based on the given sequence:
    proc makeThingList(tlist: seq[Thing]): VNode =
        result = buildHtml(tdiv(class="thing-list")):
            for idx, th in tlist:
                tdiv(id=th.uid, class="thing " & evenOdd(idx)):
                    text kstring($th)
    
    
    # Make/render the controls button and the text inputs
    # necessary to create new thingies:
    proc makeControls(state: var AppState): VNode =
        result = buildHtml(tdiv(class="controls")):
            label(`for`=IdInputThingName):
                    text "Thing Name: "
            input(`type`="text", id=IdInputThingName, 
placeholder=kstring("Input the thing name here..."))
            label(`for`=IdInputThingDesc):
                text "Thing Description: "
            input(`type`="text", id=IdInputThingDesc, 
placeholder=kstring("Input the thing desc here..."))
            button(onclick=actionAddThing(state)):
                text "Add Thing"
    
    
    # Make/render the whole dom (return closure for karax):
    proc createDom(state: var AppState): proc(): VNode =
        return proc(): VNode =
            result = buildHtml(tdiv(id="things-are-dope")):
                makeThingList(state.getAllThings())
                makeControls(state)
    
    
    
    when isMainModule:
        # Initialize app state as variable because I want to change it's 
insides later
        # (this is probably a bad idea...)
        var state = newAppState()
        
        # Add few things into the app state's list of things:
        state.addThing(thingFactory("Thing A", "Desc about Thing A"))
        state.addThing(thingFactory("Thing B", "Desc about Thing B"))
        state.addThing(thingFactory("Thing C", "Desc about Thing C"))
        
        # Now we are ready to create the DOM:
        setRenderer createDom(state)
    
    
    Run

I'm hopeful that this isn't again in the series of stupid questions... :)

Reply via email to