astoilkov / jsblocks Goto Github PK
View Code? Open in Web Editor NEW2012 UI framework (I was 20 years old, React didn't exist, inspired by Knockout)
Home Page: http://jsblocks.com
License: Other
2012 UI framework (I was 20 years old, React didn't exist, inspired by Knockout)
Home Page: http://jsblocks.com
License: Other
Compiling a chain into a raw callback composition is a very good idea. As of now, there are some bugs with it.
An exemple is better than long explanations. The following code:
blocks([0,1,2])
.each(function(v) { console.log('first each', v); })
.each(function(v) { console.log('second each', v); })
.map(function(v) { console.log('first map', v); return v; })
.map(function(v) { console.log('second map', v); return v; })
.value();
is logging this:
first each 0
first each 1
first each 2
first each 0
second each 0
first each 1
second each 1
first each 2
second each 2
first each 0
second each 0
first map 0
second map 0
first each 1
second each 1
first map 1
second map 1
first each 2
second each 2
first map 2
second map 2
We see 2 things:
This framework needs more jQuery.
I noticed the chaining reduce
is one off of the non-chaining version. For reference see the current micro-benchmark we've discussed.
Like AngularJS directives or KnockoutJS components?
As would the use of templates recursively, see example:
JS:
var Menus = blocks.observable([{label: 'test1', menu: [{label: 'sub_test1', menu:[]}]}, {label: 'test2', menu: []}, {label: 'test3', menu: []}]);
HTML:
<script id="item_menu" type="text/blocks-template">
<div data-query="each($this)">
<h3>{{label}}</h3>
<p>{{menu.length}}</p>
<div data-query="visible(menu.length > 0).template('item_menu', menu)"></div>
</div>
</script>
<div data-query="template('item_menu', Menus)"></div>
RESULT:
test1
1
{{label}}
{{menu.length}}
test2
0
test3
0
Your site (http://jsblocks.com/) doesn't appear to work at the moment.
Was looking for complete todo app , and didnt find it. Please consider adding it to todomvc.com
There is currently no way to specify what happens on an unmatched route.
I propose a user should be able to set this as part of view.options as follows:
App.View('404', {
options: {
defaultRoute: true
}
}
This will allow a application to specify it's 404 view, or pass a bad request to the home page for example.
I tried to reproduce the same behavior as in my previous ticket (#7) and I think I know what's going on. It seems that nested views with lazy loaded templates are not working correctly.
For example, if I take the example from the Nested views page and I "convert" the Navigation/Article view with a lazy loaded template, it still works fine. However, when I also replace the Blog view with a lazy loaded template, then that view is still rendered correctly, but the child views no longer load.
Here's a small Plunker code example showing the issue: http://plnkr.co/edit/OJDNpDdo8XDDFw37MFbs?p=preview
Is it possible to convert a JS object to an observable / observableArray? Each object should, of course, an observable object.
e.g.
var array = [{foo:'bar},{bar:'foo'}];
var observableArrayWithObservables = blocks.toObservable(array);
So, I'm not sure if this is actually a problem or if I've missed an important detail here, but I can't seem to find a way to solve it. I created a model following the example of dependency observables and model introduction and it worked just fine.
However, if I do that and push multiple of these models into a collection, the observable is not evaluated correctly anymore.
I'm using the following code:
var App = blocks.Application();
var Cake = App.Model({
cakeType: blocks.observable(),
cakeSize: blocks.observable(),
fullCake: blocks.observable(function() {
return this.cakeType() + 'cake (' + this.cakeSize() + ')';
})
})
var Cakes = App.Collection(Cake);
App.View('Bakery', {
cakes: Cakes([
{ cakeType: 'strawberry', cakeSize: 'small' },
{ cakeType: 'chocolate', cakeSize: 'large' }
])
});
<div data-query="view(Bakery)">
<div data-query="each(cakes)">
<h2>Let's eat some, {{fullCake}}!</h2>
Type: <input data-query="val(cakeType)" />
<br />
Size: <input data-query="val(cakeSize)" />
</div>
</div>
You would expect this to display Let's eat some, strawberrycake (small)
and Let's eat some, chocolatecake (large)
. However, while the input values are displayed correctly, the dependency obsevable returns Let's eat some, strawberrycake (small)
in both entries.
I haven't found a solution for this yet, the error also occurs using {{this.fullCake}}
or {{$this.fullCake}}
I want to create a clear button for a text field that is being observed. It works, from the standpoint that the button clears the content of the field. But the two-way binding is not updated when this happens. Is there either an internal way to change the bound value, or an event I can fire that will wake up the binding to the new value?
Can this be used with jQuery?
I get this error when I load jQuery on a page with jsblocks.
TypeError: Cannot call method 'createElement' of undefined
at assert (eval at (c:\Users\bclarke\Work\code\factory\src\jsblocks\auth\node_modules\blocks\node\blocks-node.js:11690:23), :15378:21)
at eval (eval at (c:\Users\bclarke\Work\code\factory\src\jsblocks\auth\node_modules\blocks\node\blocks-node.js:11690:23), :17046:24)
at Config.api.me (eval at (c:\Users\bclarke\Work\code\factory\src\jsblocks\auth\node_modules\blocks\node\blocks-node.js:11690:23), :17097:3)
at arr (eval at (c:\Users\bclarke\Work\code\factory\src\jsblocks\auth\node_modules\blocks\node\blocks-node.js:11690:23), :14520:3)
at eval (eval at (c:\Users\bclarke\Work\code\factory\src\jsblocks\auth\node_modules\blocks\node\blocks-node.js:11690:23), :14524:2)
at c:\Users\bclarke\Work\code\factory\src\jsblocks\auth\node_modules\blocks\node\blocks-node.js:11693:19
at contextBubble (c:\Users\bclarke\Work\code\factory\src\jsblocks\auth\node_modules\blocks\node\blocks-node.js:11710:5)
at executeCode (c:\Users\bclarke\Work\code\factory\src\jsblocks\auth\node_modules\blocks\node\blocks-node.js:11683:5)
at executePageScripts (c:\Users\bclarke\Work\code\factory\src\jsblocks\auth\node_modules\blocks\node\blocks-node.js:11678:5)
at Object.Middleware._renderContents (c:\Users\bclarke\Work\code\factory\src\jsblocks\auth\node_modules\blocks\node\blocks-node.js:12153:9)
I'm trying to combine jsblock with websockets using socket.io, however I can't figure out how to update a view from outside (from the callback of the socket) any ideas on how to get about this?
EDIT: I forgot to include to code I'm using
'use strict';
var App = blocks.Application();
var Message = App.Model({
author: App.Property({
defaultValue: 'anonymous'
}),
message: blocks.observable()
});
var Messages = App.Collection(Message, {
even: blocks.observable(function () {
return this().length % 2 == 0;
})
});
App.View('Chat', {
name: 'Wannes Gennar',
newMessage: Message(),
init: function () {
this.socket = io('http://localhost:3000');
this.messages = Messages();
var service = this;
console.log(service);
this.socket.on('chat message', function (msg) {
service.messages.push({
message: msg
});
});
},
addMessage: function () {
this.socket.emit('chat message', { author: this.newMessage.author, message: this.newMessage.message });
this.newMessage.reset();
},
up: function(e)
{
if (e.which === 13)
this.addMessage();
}
});
The API documentation of the with()
query is confusing. The examples are using view(ViewName, '$context')
in stead of with()
. Is it meant to be used with the view()
query, or are the examples wrong?
The problem could be replicated in the jsblocks TodoMVC example.
My first my example app
https://github.com/SubKit/sk-todo-app/tree/master/src/jsblocks
the initial load and rendering time is slow. It flickers when starting. Any ideas?
Chrome extensions do not allow code generation from strings. The John Doe example errs with
Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self' chrome-extension-resource:".
Consider adding CSP mode in the future.
I want to use jsblocks within swig[https://github.com/paularmstrong/swig]. Apparently, {{}} is used for expressions in both.
Hello,
If possible, please update your angular.js performance test cases with track by $index
in each of the ng-repeats
in order to even the playing field.
initial-load/angular.html
<tr ng-repeat="person in people track by $index">
<td ng-repeat="column in columns track by $index">
{{person[column]}}
</td>
<td ng-repeat="column in columns track by $index">
{{person[column]}}
</td>
</tr>
syncing-changes/angular.html
<tr ng-repeat="person in people track by $index">
<td ng-repeat="column in columns track by $index">
{{person[column]}}
</td>
<td ng-repeat="column in columns track by $index">
{{person[column]}}
</td>
</tr>
You always start resolution of super from the this
, so you can trap in infinite recursion.
e.g
Class1
method
Class2 extends Class1
method -> here we have this.super('method')
Class3 extends Class2
method -> here we have this.super('method')
inst = new Class3().method();
When you call this.super('method') in Class3 you will indeed call the Class2.method but there this will refer inst
object. So when you try to call super again the resolution will be again Class2.method.
The best fix of this is to not use it at all.
Hi,
I have a index.html structure like:
<header id="header" data-query="view(HeaderView)"></header>
<section id="main">
<aside id="sidebar" data-query="view(SideBarView)"></aside>
<section id="content"></section>
</section>
In SideBar view, there are links for content like navigateTo(DasboardView)
or navigateTo(UserProfileView)
.
I am loading views with requirejs like this:
define(function (require) {
var App = blocks.Application();
var HeaderView = require('./views/HeaderView');
var UserProfileView = require('./views/UserProfileView');
App.start();
});
Load that clicked link target view in content
section dynamically. With 'dynamically', I mean loading of View without defining it in html, for example without defining these in content section:
<div class="container" data-query="view(DasboardView)"></div>
<div class="container" data-query="view(UserProfileView)"></div>
Is it possible with jsblocks framework without breaking route history support?
Hi Antonio,
I have to init some jquery plugins after the view(and its template) is mounted to DOM. I tried view's routed
callback but it seems this callback is too early for this task. I can only do initialization of plugins by waiting in setTimeout
. Is there a better way?
Regards,
jsvalue - the built-in utility methods in jsblocks are having more problems than solving ones. The best option is to remove the utility methods by default and release it as a separate library. Only if it becomes stable enough it could get part of some jsblocks built. It should be people decision by default which library to use. Also jsblocks will introduce integration with lodash and underscore by default so the same experience is achieved when using those libraries.
I have tried writing an application that is hooked up to a server, basically it was creating a record as stated in the documentation, and combined that with the Collection/List approach.
The problem is, when I run the code that is presented in the documentation, it - obviously - works. If I embed this code in something similar to the list example on the homepage, it doesn't sync correctly. So I went back to the Cake
test script and tried to reproduce it using the following code:
var App = blocks.Application();
var Cake = App.Model({
cakeType: blocks.observable(),
cakeSize: blocks.observable(),
fullCake: function(self) {
return self.cakeType() + 'cake (' + self.cakeSize() + ')';
},
})
var Cakes = App.Collection(Cake);
App.View('Bakery', {
newCake: Cake(),
cakes: Cakes([
{ cakeType: 'strawberry', cakeSize: 'small' },
{ cakeType: 'chocolate', cakeSize: 'large' }
]),
bakeCake: function() {
this.cakes.add(this.newCake);
console.log(this.newCake.cakeType()); // TEST OUTPUT
this.newCake.sync();
this.newCake.reset();
}
});
<div data-query="view(Bakery)">
<div>
<h2>Let's eat some, {{newCake.fullCake(newCake)}}!</h2>
Type: <input data-query="val(newCake.cakeType)" />
<br />
Size: <input data-query="val(newCake.cakeSize)" />
<button data-query="click(bakeCake)">Bake!</button>
</div>
</div>
The problem is, while the request to the respective create url
- which isn't given in this example but it doesn't make a difference - is successfully sent, it does not contain any request payload. So I'm basically sending an empty payload to the server.
Loggin the data via console.log
at the "TEST OUTPUT" does show, that the Model actually contains data but it's not serialized and packed into the request.
Error:
TypeError: ElementsData.data(...) is undefined --> blocks.js (línea 10115, col 21)
bad: data-query="each(items.view)"
http://jsblocks.com/api/blocks-queries-each
There is no possibility to make 2 cycles with different $this
Better, but ugly syntax: data-bind="foreach: { data: categories, as: 'category' }"
http://knockoutjs.com/documentation/foreach-binding.html
Best but not compatible: ng-repeat="model in collection" https://docs.angularjs.org/api/ng/directive/ngRepeat
angular-like syntax is powerful, but this is not pure js
proposal 1:
data-query="each(collection)" data-iterator="model" (for array)
data-query="each(collection)" data-iterator-key="key" data-iterator-key="value"
it's possible to make 2 nested loops with different iterators. A little bit bloat syntax for array and really bloat syntax for objects
proposal 2:
data-query="each(collection, index, value)" (for array)
data-query="each(collection, key, value)" (for object)
better syntax, but index, key and value are not defined, so workaround will be not very simple and clear. Not extendable with new stuff
proposal 3:
data-query="each(collection).index('index_name').value('value_name')" (for array)
data-query="each(collection).key('key_name').value('key_name')" (for object)
more text, but it's javascript. There is not such big problem to extend "key", "index" and "value" methods.
proposal 4:
data-query="as({index:'index'}).each(collection)"
even better, but a little bit strange order.
There is no need to change each(), you only add "as" data-query with method "each".
proposal 4.1:
data-query="index('index').each(collection)"
proposal 3 + proposal 4 combination. Fully compatible with proposal 4
Hi astoilkov,
I am having difficulty trying to make a view re-usable so that 2 copies can coexist on a page at the same time with different options.
Is there any way to pass options to a view with a data-query?
I would like to do something like this:
data-query(view(MyView, { id: 1}))
data-query(view(MyView, { id: 2}))
However, the view method does not accept options as a parameter.
I tried making a custom data-query like this but am struggling to get it to work.
data-query(portlet(MyView, { id: 1}))
blocks.queries.portlet = {
preprocess: function (param1, param2) {
this.html('<div id="'+param1+'" data-query="view('+param1+')"></div>');
blocks.query(param2);
}
};
<script src="http://jsblocks.com/blocks/0.3.2/blocks.js"></script>
<script type="text/javascript">
(function (blocks, undefined) {
var App = blocks.Application();
function keydown(e) {
if (e.which === 13) {
this.folders.add(this.newFolder);
this.newFolder.reset();
}
}
var SubFolder = App.Model({
name: App.Property(),
editing: blocks.observable(false),
toggleEdit: function () {
this.editing(!this.editing());
},
remove: function () {
this.destroy(true);
console.log("remove");
}
});
var Folder = App.Model({
name: App.Property(),
folders: App.Collection(SubFolder)(),
editing: blocks.observable(false),
toggleEdit: function () {
this.editing(!this.editing());
},
remove: function () {
this.destroy(true);
},
newFolder: SubFolder(),
addSubfolder: keydown
});
var Folders = App.Collection(Folder);
App.View("Folders", {
newFolder: Folder(),
folders: Folders(),
keydown: keydown
});
})(window.blocks);
</script>
<div id="folders" data-query="view(Folders)">
<input type="text" id="addFolderInput" data-query="val(newFolder.name).keydown(keydown)" placeholder="Add new folder and press enter" />
<div data-query="each(folders)">
<div class="folder">
<span data-query="visible(!editing())" class="folderName">
{{name}}
</span>
<span data-query="visible(editing)">
<input type="text" data-query="val(name)" />
</span>
<span class="buttons">
<span data-query="click(toggleEdit).setClass('icon-checkmark', editing).setClass('icon-pencil', !editing())"></span>
<span data-query="click(remove)" class="icon-bin"></span>
</span>
<div id="newSubfolder">
<input type="text" id="addSubfolder" data-query="val(newFolder.name).keydown(addSubfolder)" placeholder="Add new subfolder and press enter" />
</div>
<div id="subfolders" data-query="each(folders)">
<div class="folder">
<span data-query="visible(!editing())" class="folderName">
{{name}}
</span>
<span data-query="visible(editing)">
<input type="text" data-query="val(name)" />
</span>
<span class="buttons">
<span data-query="click(toggleEdit).setClass('icon-checkmark', editing).setClass('icon-pencil', !editing())"></span>
<span data-query="click(remove)" class="icon-bin"></span>
</span>
</div>
</div>
</div>
</div>
</div>
results in any subfolder created for any folder to populate a new folder.
Hey guys, I'm trying to use Zurb Foundation with my jsblocks app but it doesn't seem to be working.
I added some console.logs() to Foundation's init function and confirmed that it is being called.
If I npm install jsblocks I get a folder with blocks.js but the file is empty.
Hello @astoilkov. Can I use RxJS or another similar library with jsblock observable together?
In the API docs for the view()
query you have the following piece of code as example:
<!-- looping through the View users collection -->
<ul data-query="view(users)">
Shouldn't that be the each()
query?
Hi Antonio
I get ERR_CONNECTION_REFUSED error while connecting to jsblocks.com.
Hi,
I am exploring possibility to use jsblocks and materializecss in an Android app (using Crosswalk to boost performance). Is there any limitation that I need to know? I understand right now that jsblocks can be used for both web and hybrid mobile app (as in Ionic or OnSen UI). However I don't know if it works well with Cordova/Phonegap or not. My feeling is that I can integrate 2 JS framework together without any issue because there is no conflict in architecture.
Thanks
Dinh
I'm quite confused about nested views. According to the documentation you should add the name of the parent view, for example:
App.View('Parent', {});
App.View('Parent', 'Child', {});
In the API docs on the other hand, there is no reference of this parent/child declaration.
I'm having quite a lot of problems with this setup, I'm always getting the same error in my log:
Uncaught ReferenceError: Child is not defined
And I'm pretty sure that part of the script is executed. Also, when you switch the order, for example:
App.View('Parent', 'Child', {});
App.View('Parent', {});
I'm noticing that there's a high CPU usage and the page freezes.
Also, this doesn't really makes sense to me. I'm trying to make an individual component (for example a user profile component), but this can obviously be used in multiple parents. If I leave the parent viewname, then the component works individually, but it does not work in a nested situation.
Hi, I noticed this code in syncing-changes/react.html
var data = generateData(500);
var columns = getColumns();
React.render(
React.createElement(Table, {people: data, columns: columns}),
document.getElementById('example')
);
And for syncing-changes/blocks.html
var items = blocks.observable(generateData(100));
blocks.query({
items: items,
columns: getColumns()
});
Is this a typo? Seems a bit unfair. After correcting first example to 100, results became indistinguishable for me.
I'm trying this example: http://jsblocks.com/learn/queries-creating-a-custom-query
It doesn't work as expected.
It works when I add a line "blocks.query({})" before example.
Try yourself:
http://codepen.io/anon/pen/oXeVQe
I can't change <title>
element and everything in head
element.
I propose to make middleware after tryServerPage
, not just before it.
blocks.server({
preMiddleware: [compression()],
postMiddleware: [changeTitle()]
});
Trying to add a view with a separate HTML file and it comes back with the error..
Critical: view(Row) - exception thrown while executing query parameter <li data-query="view(Row)" data-id="20">
Is this not possible?
The values doesn't seem to be interpolated in the style
attribute. However, it works on other attributes (even with a misspelled stye
attribute).
<!doctype html>
<html>
<head>
<script src="http://jsblocks.com/jsblocks/blocks.js"></script>
<script>
window.box = {};
box.height = blocks.observable("250");
box.width = blocks.observable("250");
box.backgroundColor = blocks.observable("#fff");
blocks.query(box);
</script>
</head>
<body>
Enter Height: <input type="text" data-query="val(height)" />
Enter Width: <input type="text" data-query="val(width)" />
Enter Background Color: <input type="text" data-query="val(backgroundColor)" />
<h2>Height: {{height}}</h2>
<h2>Width: {{width}}</h2>
<h2>Background Color: {{backgroundColor}}</h2>
<div style="background-color: {{backgroundColor}}; height: {{height}}px; width: {{width}}px;"></div>
</body>
</html>
Running the sample shopping application and navigating between boys, girls, babies etc
while being lower on the page causes the page to scroll to top.
Is there anyway to prevent this?
function Model(){
this.user_input = blocks.observable();
this.headline = 'Howdy from the application';
}
blocks.query(new Model());
<h1>{{headline}}</h1>
<input data-query="val(user_input)" placeholder="Enter some text…" size="40"/> <button class="clear">×</button>
<p>{{user_input}}</p>
This works, but it throws an error unless I declare a global variable named user_input. If I put an initial value in like blocks.observable('foo'), then I don't get the error, but I also can't use a placeholder as I would like. I would like the variable to initialize to an empty string if nothing is passed into it by observable.
Hi Antonio, thanks for this elegant framework. Can you show me a quick way to add
centrally without breaking antyhing?
Regards,
E.D.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.