Comments (10)
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.
Yes, sure... Thanks
from framework.
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.
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.
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.
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.
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.
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.
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.
Hi, can I close this issue?
from framework.
Related Issues (20)
- Planned features HOT 2
- npm install issues
- Bower support + Firefox NX source download bug HOT 12
- Reference to element in the component HOT 5
- Upcoming core rework HOT 3
- Is this project alive? HOT 3
- Why doesn't `exec` return values? HOT 5
- Web components org recommendation list HOT 1
- DOM node attribute changes not caught by handler HOT 3
- [Question] Can this framework be used with a template engine? HOT 3
- [MAJOR BUG] website won't openππ HOT 4
- Surviving contact with jquery and its libraries
- Usage inside meteor (amd/import usage instead of webpack) HOT 1
- Uncaught ReferenceError: module is not defined HOT 2
- history error HOT 3
- 402: Payment required HOT 1
- What is the status of this project? HOT 1
- Add supports for clipboard events. HOT 9
- Hide elements until they are resolved. HOT 8
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google β€οΈ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from framework.