Code Monkey home page Code Monkey logo

Comments (10)

CheloXL avatar CheloXL commented on May 13, 2024 1

My framework is a custom one. It's a kind of MVVM framework/pattern implementation. You have your view (html), a controller (js class) and a model (js poco).

The html has the bindings (like <select data-bind="events: {change: onSelectChange}, value: path.to.property, source:path.to.model.list"></select>). The controller is there just to capture events and react on them, also to do something with the data (send to the server, for example :) ).

I already though in changing my observable with yours (that's how I found nx, by searching for something similar to what I wrote), but since my observable fires events without delays and the framework expects that to happen, I simply decided to start looking at yours instead of trying to refactor mine.

Thanks for the example, will take a look later today πŸ‘

from framework.

CheloXL avatar CheloXL commented on May 13, 2024 1

Yes, sure... Thanks

from framework.

solkimicreb avatar solkimicreb commented on May 13, 2024

I am not sure that I understand. The DOM mapped to the iterable items always receives an inheriting state with the current item. It means that it can access the current item and everything from the parent state, which is not shadowed by its own state (its dead simple prototypal inheritance.) A copy-paste example for your use case:

<script src="http://www.nx-framework.com/downloads/nx-beta.1.1.0.js"></script>
<script>
  nx.components.app()
    .use((elem, state) => state.names = ['Anne', 'Bob', 'John'])
    .register('test-app')
</script>

<test-app>
  <div @repeat="names" repeat-value="name">
    <p>name is: ${name}, names are: ${names}</p>
  </div>
</test-app>

The same would be true in javascript code and the state object. In case of custom components (not native DOM elements), you can manually play around with their state setting. Components can define new state (default), an inheriting state or no state at all. See the component configuration part in this docs section for more.

The default true state setting of custom components overwrites the inheriting state from @repeat and it creates a totally blank new state for the component. You can fix this by adding an inheriting state to the comp or by creating a stateless comp with state: 'inherit' or state: false. Copy-paste example:

<script src="http://www.nx-framework.com/downloads/nx-beta.1.1.0.js"></script>
<script>
  nx.components.app()
    .use((elem, state) => state.names = ['Anne', 'Bob', 'John'])
    .register('test-app')

  nx.component({state: 'inherit'})
    .register('name-comp')
</script>
<style> name-comp {display: block;} </style>

<test-app>
  <div @repeat="names" repeat-value="name">
    <name-comp>name is: ${name}, names are: ${names}</name-comp>
  </div>
</test-app>

This creates a comp with an inheriting state, which sees person and people (just like the original case with no comp).

This is nice for specific use cases, but for general reusable components you should use stateful components with injectable dependencies. This is what the attributes middleware and custom attributes are useful for. Copy-paste example:

<script src="http://www.nx-framework.com/downloads/nx-beta.1.1.0.js"></script>
<script>
  nx.components.app()
    .use((elem, state) => state.names = ['Anne', 'Bob', 'John'])
    .register('test-app')

  nx.component()
    .use((elem, state) => {
      elem.$attribute('name', name => state.name = name)
      elem.$attribute('names', names => state.names = names)
    })
    .register('name-comp')
</script>
<style> name-comp {display: block;} </style>

<test-app>
  <div @repeat="names" repeat-value="name">
    <name-comp @name="name" @names="names">name is: ${name}, names are: ${names}</name-comp>
  </div>
</test-app>

The name and names $attribute handlers are very simple ones, they inject the value into the comp's state. Notice the @ prefix before the attributes. It means that whenever the parent name or names changes the attribute handler reruns and updates the comp's name and names.
The <name-comp @name="name" @names="names">name is: ${name}, names are: ${names}</name-comp> line can be rewritten as <name-comp @name @names>name is: ${name}, names are: ${names}</name-comp> with the shorthand attributes syntax. See more about custom attributes here or check the story-list and story-item components in the Hacker News example for a real-life example.

Sorry for the late response, I missed this issue somehow. I hope the answer is helpful (:

from framework.

solkimicreb avatar solkimicreb commented on May 13, 2024

I might tweak this a bit in the next release. The question is what to do when a stateful component is added right inside a repeat block? The user probably wants to use the current item inside the comp and expects it to be available without any hassle, but at the same time a stateful components is expected to be initialized with a blank new state. Should I make an exception and add the current item to the state of stateful components in this case, or maybe display a warning? What's your opinion about this?

from framework.

CheloXL avatar CheloXL commented on May 13, 2024

My problem is not about what is inside the repeater, but with the repeater per-se. My stateful component IS the repeater. The inner components are normal components/controls that may modify the item to which they are attached to.

So, basically:

<repeater-widget>
  <div @repeat="names" repeat-value="name">
    <div class="row">
      <div>
        <input name="name" bind="two-way input" autocomplete="off">
      </div>
      <button #click="deleteRow">[-]</button>
    </div>
  </div>
  <div class="row add">
    <button #click="addRow">[+]</button>
  </div>
</repeater-widget>

The input is bound as usually. The above should show a list of names, where on each row you have the ability to delete it (by clicking on the [-]), or add a new row (by clicking on the [+]) that will show an empty input so you can fill in it.

The above example is what I would need in terms of functionality but not in terms of code. In terms of code I need something simpler, like

<repeater-widget source="names" [value="name"]>
	<input name="name" bind="two-way input" autocomplete="off">
</repeater-widget>

Where "value" may or may not be specified. The widget then should have to transparent handle the add/remove, etc.

from framework.

solkimicreb avatar solkimicreb commented on May 13, 2024

I see now. I would say that composable reusable components like this should be implemented with the shadow DOM slotting api, since you compose together your component's internal DOM (the add/remove functionality) and the external user defined DOM (the input). Shadow DOM flavored composing is available without the shadow DOM too. I will write a small example soon.

Small correction of the above code: you should do #click="addRow()" instead of #click="addRow". Event handlers always execute the given code on an event.

Off topic: I would be grateful for some feedback about which parts of NX feels clumsy and not right in your opinion?

from framework.

CheloXL avatar CheloXL commented on May 13, 2024

Ahh.. thanks. Do you think it would be possible to define the template inside the component definition, like I shown in the example above? Also, yes... I typed the code directly on github so it's not a real working code.

Regarding the feedback: Sure, I would like to, but I'm still getting used. Since I'm using my own framework (that I wrote 5 years ago) and it is quite different in its philosophy, I'm still wrapping my head around (also, since my framework is being used in production in my current work, I'm mostly playing with nx right now).

The only thing in common between frameworks is the observable object, that I built using accessors (not proxies). And because that transparency is why I choose nx to start playing with (I hate all that frameworks where you have so tell the framework in some way that you changed a property).

from framework.

solkimicreb avatar solkimicreb commented on May 13, 2024

Single file comps are not yet supported, but people generally like them so I will implement them in the future. For now the best practice is to put your comp's JS, HTML and CSS in separate files and bundle them with webpack.

What's your framework? The observer part of NX is completely independent and pluggable. (It is plugged in by a very short middleware). You could integrate it with your framework if you would like too πŸ™‚

Example widget is in the making.

from framework.

solkimicreb avatar solkimicreb commented on May 13, 2024

Here is a copy-paste example:

<script src="http://www.nx-framework.com/downloads/nx-beta.1.1.0.js"></script>

<script>
  nx.components.app()
    .use((elem, state) => state.names = ['Anne', 'Bob', 'John'])
    .register('test-app')

  nx.components.rendered({
    template: `<input name="newItem" bind #change="addItem()" />
               <div @repeat="source" $repeat-value="value">
                  <div>
                    <slot name="item"></slot>
                    <button #click="removeItem($index)">Remove</button>
                  </div>
                </div>`
  }).use(setup).register('repeater-widget')

  function setup (elem, state) {
    elem.$attribute('source', source => state.source = source)
    elem.$attribute('value', value => state.value = value)

    state.addItem = () => state.source.push(state.newItem)
    state.removeItem = (index) => state.source.splice(index, 1)
  }
</script>

<!-- testing the widget -->
<test-app>
  <repeater-widget @source="names" value="name">
    <p slot="item">name is: ${name}</p>
  </repeater-widget>
</test-app>

The widget is created from a rendered component as it uses the render middleware by default. The template is passed as a string for simplicity, but it should be in a spearate file and required with require(./template.html) and bundled with webpack - just like in the Hacker News example.

The render middleware supports Shadow DOM styled slotting, meaning that you can compose external and internal DOM with slots. I defined a single slot for the repeated item, but you could define slots for the remove button and the add input for greater flexibility. I hope it is clear, slotting can take some time to get used to, but it is super useful.

from framework.

solkimicreb avatar solkimicreb commented on May 13, 2024

Hi, can I close this issue?

from framework.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.