marko-js / marko Goto Github PK
View Code? Open in Web Editor NEWA declarative, HTML-based language that makes building web apps fun
Home Page: https://markojs.com/
License: MIT License
A declarative, HTML-based language that makes building web apps fun
Home Page: https://markojs.com/
License: MIT License
Hi,
Whats the best way to pass data to components. At present it appears you have to pass data from every template to the components e.g. in index.marko you would have
<app-header title="$data.title" env="$data.env" csrf="$data.csrf"></app-header>
I can then access the data from the component e.g.
<if test="data.env == 'development'">
If I try to access data.env without passing the data in from index.marko I get an error. Doing it this way if I want to pass new data into the app-header component in the future I would have to change ALL templates.
Is there a better way of doing this?
Thanks,
Pat (new to Marko and Node)
Usecase:
We would like to add a library of components. The path would be:
/node_modules/component-library/node_modules/custom-component/lib/
If the rendered template is somewhere else then this path won't be discovered.
Suggestion:
Add a way to add paths to the discovery feature
This is not supported
template.renderSync({
$global: {
foo: "foo!"
}
});
But this is (as seen in #16)
template.render{
$global: {
name: 'Frank'
}
}, res);
The issue seems to be that $global
processing is missing from the renderSync
function.
https://github.com/raptorjs/marko/blob/master/runtime/marko-runtime.js#L65-L72
Template.prototype = {
renderSync: function(data) {
var out = new AsyncWriter();
out.sync();
this._(data, out);
out.end();
return out.getOutput();
}
But can be found in the render
function.
https://github.com/raptorjs/marko/blob/master/runtime/marko-runtime.js#L84-L126
render: function(data, out, callback) {
...
var $global = data.$global;
if ($global) {
extend(out.global, $global);
}
c-input
works well for nested tags, but there are times when we need to pass down extra information from the parent tag, like this:
<tagname c-input="data.someObj" attribute="test"/>
Examples include when the parent contains the loop and we might need an index in the nested tag, or if parent tag-level logic affects a child tag.
This should also include support for passing a conditional, or at least a variable (that we can set with a conditional earlier in the file).
Thanks!
I am trying to target IE browsers with some simple IE conditionals, but it seem to fail in marko template.
My template has these simple conditionals, but its not getting targeted properly. I donโt see the classes being added. (works however in plain html)
<!--[if lt IE 7]> <html class="lt-ie9 lt-ie8 lt-ie7" lang="${locale}"> <![endif]-->
<!--[if IE 7]> <html class="lt-ie9 lt-ie8" lang="${locale}"> <![endif]-->
<!--[if IE 8]> <html class="lt-ie9" lang="${locale}"> <![endif]-->
<!--[if !IE]> --><html lang="${locale}"><!--<![endif]โ>
anything to do with the HTML commentโs?
Hi,
I need to define my custom tags using marko
node module but not using JSON files described here.
Maybe there is something like that?
var marko = require('marko');
marko.defineTag('my-hello', {
renderer: require('./hello-renderer'),
attributes: {
name: 'string'
}
});
Example:
<some-component c-input="{ message: 'Hello World' }"/>
src/components/some-component/renderer.js:
module.exports = function render(input, out) {
var message = input.message; // 'Hello World'
}
"template-data" is similar, but it only works for includes. Only one should be documented for consistency.
Hey,
This might be a hard thing to integrate, but I'd like to discuss it, maybe you will find it useful.
What want to accomplish is to load a component dynamically. Instead of using a html tag, I want to load it through a dedicated attributes value, lets say 'taglib'-attribute.
<div for="item in data.components" taglib="$!{item.component}-component" model="$!{item.value}">
or
<div for="item in data.components" taglib="item.component" model="$!{item.value}">
The problem is, if we'd like to be able to use every template available, we would need some sort of index with template names and their relative path. Alternatively, we could scope the available templates to only a certain directory, which would be easier, but not as clean.
This would require us to have a compiled template like this.
templates = { "component-one": "./components/component-one/template.marko" };
return function render(data, out) {
out.w('xxx');
forEach(data.components, function(item) {
__helpers.l(require.resolve(templates[item.component])).render({"value": str(item.value)}, out);
});
out.w('xxx');
};
or
templates = {
"component-one": __helpers.l(require.resolve("./components/component-one/template.marko"))
};
return function render(data, out) {
out.w('xxx');
forEach(data.components, function(item) {
templates[item.component].render({"value": str(item.value)}, out);
});
out.w('xxx');
};
Of course we could check, if array contains element etc. This is just a dirty example. I know that this adds a bit of an overhead to the lightweight templates, especially if you got lots of components, but I couldn't think of any different/better way of doing this without sacrificing client-side compatibility. What do you think?
I could integrate it, though it will take me some time to dive into the code. A few hints where I find the responsible bits would surely help me.
Hi there,
i had an issue with adding following text in the marko template
hello world <> hello
after some debuging i found a problem within htmlparser2 module, and after submitting a pull request with fix to htmlparser2 module, author closed it and attached to other ticket ... at the end of the ticket he clearly says that he will not fix all the outstanding issues soon: "I have no idea when I'll have the time & be motivated to do it, so I can't give a timetable or anything" so maybe you should thing moving to other html parser because lacking of support.
the Html color highlighting is not good enough for marko template files in Sublime, it will be great if we can create one for Marko templates
Hello,
is there a way to work with marko and webpack, a marko-loader perhaps ?
Thanks
When using:
template.render(data, callback);
Internally we create an AsyncWriter instance, but it is not made available to the caller when using a callback function. To allow access to the AsyncWriter instance we should invoke the callback with 3 arguments: callback(err, html, out)
We should allow prefixes to be provided when scanning for tags within a directory.
For example, to scan single directory:
{
"tags-dir": {
"path": "./components",
"prefix": "app-"
}
}
To scan multiple directories:
{
"tags-dir": [
{
"path": "./components",
"prefix": "app-"
},
{
"path": "./components/chat",
"prefix": "chat-"
}
]
}
The $global property is used to add data that is available to all templates encountered during rendering by having the data hang off the wrapped writer.
template.render{
$global: {
name: 'Frank'
}
},
res);
Given the following template:
<div>
Hello ${out.global.name}!
</div>
The output would be the following:
<div>
Hello Frank
</div>
<my-first-tag>
<my-second-tag>
The new line between these two custom tags should be preserved.
Is it possible to programmatically call taglibs?
Currently we can do the following when including template fragments:
<include template="src/modules/${module.alias}.marko"/>
I can include a different template based on the value of "module.alias".
I'd like to be able to have the same logic with taglibs. Something like this:
<var name="path" value="data.type" />
<app-test-${path} attr1="${data.attr1}" attr2="${data.attr2}" attr2="${data.attr2}"/>
Currently I can do the following:
<if test="data.type === "a">
<app-test-a attr1="${data.attr1}" attr2="${data.attr2}" attr2="${data.attr2}"/>
</if>
<else-if test="data.type === "b">
<app-test-b attr1="${data.attr1}" attr2="${data.attr2}" attr2="${data.attr2}"/>
</else-if>
<else>
<app-test-c attr1="${data.attr1}" attr2="${data.attr2}" attr2="${data.attr2}"/>
</else>
This would work but I'd like to avoid having to copy over the same parameter code.
Currently, when using a custom tag that allows nested body content we compile the body content to a function that, when invoked, renders to the out
from the closure. For example:
exports.create = function(__helpers) {
var __renderer = __helpers.r,
button_tag = __renderer(require("../button-tag")),
__tag = __helpers.t;
return function render(data, out) {
__tag(out,
button_tag,
{
disabled: false
},
function() {
out.write('My Button Label');
});
};
};
This allows invokeBody()
to be invoked without any arguments. However, this is problematic for a few reasons:
out
requires that the custom tag to be redeclared with an additional out
variable that masks the out
from the closureinput.invokeBody()
method with the desired out
.To solve these problems, we are planning on making the following change:
input.invokeBody(...)
in favor of input.renderBody(out)
input.renderBody(out)
method, the out
must always be provided as the first argument. For example:out.write('<button type="button">');
input.renderBody(out);
out.write('</button>');
The updated compiled template will be similar to the following:
exports.create = function(__helpers) {
var __renderer = __helpers.r,
button_tag = __renderer(require("../button-tag")),
__tag = __helpers.t;
return function render(data, out) {
__tag(out,
button_tag,
{
disabled: false
},
function(out) {
out.write('My Button Label');
});
};
};
Finally, a new "body-function"
property will be offered that allows the body content of a custom tag to be converted to a custom property on the input. For example:
{
"body-function": "buildTabs(tabs)"
}
Sample compiled output:
exports.create = function(__helpers) {
var __renderer = __helpers.r,
tabs_tag = __renderer(require("../tabs-tag")),
__tag = __helpers.t;
return function render(data, out) {
__tag(out,
tabs_tag,
{
title: "My Tabs",
buildTabs: function(tabsHelper) {
...
}
});
};
};
Let's introduce a new tag attribute that will do the same thing as body-only-if
.
Most of the time the intention is to skip the container and the focus is less in the body.
<a href="${data.linkUrl}" body-only-if="!data.linkUrl">
Some body content
</a>
Can get changed to:
<a href="${data.linkUrl}" render-tag-if="data.linkUrl">
Some body content
</a>
I was struggling with this issue for an hour until one of our coworkers told me how to do it.
Please add it to the documentation. ( to reassign a value to an existing variable we need to use assign)
<assign var="itemModel" value="items[itemIndex]" />
Instead of receiving the body content as a renderBody(out)
function, it is sometimes helpful to have the body content be made available as a String property.
Proposal: Add support for a new "body-property": "<property_name>"
. For example, to map the body content (if any) to a "label" property:
{
"attributes": {
"label": "string"
},
"body-property": "label"
}
This allows the following:
<fancy-button label="My Label"/>
<fancy-button>
My Label
</fancy-button>
In both cases, the label can be read in as input.label
.
The <preserve-whitespace>
tag would produce no output, but it should tell the Marko compiler to not remove whitespace for nested nodes. This tag can be used an alternative to the c-whitespace="preserve"
attribute when there is no convenient parent element to apply the attribute to. See discussion in Issue #10.
Most renderers look similar to this:
var template = require('marko').load(require.resolve('./template.marko'));
module.exports = function(input, out) {
template.render(input, out);
};
Add support for these convenient alternatives:
module.exports = require('marko').renderer(require.resolve('./template.marko'));
module.exports = require('marko').renderer(
require.resolve('./template.marko'),
function(input) {
return {
..
}
});
NOTE: Lazily load the template that is provided and then store reference to loaded template.
Example usage:
<marko-compiler whitespace="preserve" />
Any value under the value
attribute are referenced to marko objects
but the same is not true for custom tags.
<assign var="options" value = "util.getOptions(options, pattern)" />
Custom Tag only accepts $DATA
<ebayui-refit-itemgrid-pattern viewModel = $grid options = $options />
The below code will through an error in marko
<ebayui-refit-itemgrid-pattern viewModel = "grid" options = "options" />
Marko should promote one way of passing variables to support consistency.
Especially with regards to breaking changes and feature deprecations.
It will help us make informed decisions about if/when to upgrade and what app-changes we need to make to stay up to date with the latest and greatest.
We have gotten ourselves into trouble a few times with mismatched versions between marko and supporting modules. I think having an accurate Changelog on each module would be hugely helpful in tracking down where we went awry.
Thanks!
For example:
{
"renderer": "./code-highlighter",
"preserveWhitespace": true
}
This would prevent having to do something like:
<code-highlighter c-whitespace="preserve">
This is
sample
code
</code-highlighter>
layout-use throws "SyntaxError: Unexpected token ILLEGAL"
module.exports = function create(__helpers) {
var str = __helpers.s,
empty = __helpers.e,
notEmpty = __helpers.ne,
______layouts_default_layout_marko = __helpers.l(require.resolve("../../layouts/default-layout.marko")),
node_modules_marko_node_modules_marko_layout_use_tag = require("node_modules\\marko\\node_modules\\marko-layout\\use-tag"),
_tag = __helpers.t,
node_modules_marko_node_modules_marko_layout_put_tag = require("node_modules\\marko\\node_modules\\marko-layout\\put-tag");
return function render(data, out) {
_tag(out,
node_modules\marko\node_modules\marko_layout\use_tag,
{
"template": ______layouts_default_layout_marko,
"*": {
"showHeader": true
}
},
function(_layout) {
out.w(' ');
_tag(out,
node_modules\marko\node_modules\marko_layout\put_tag,
{
"into": "title",
"layout": _layout
},
function() {
out.w('My Page');
});
out.w(' ');
_tag(out,
node_modules\marko\node_modules\marko_layout\put_tag,
{
"into": "body",
"layout": _layout
},
function() {
out.w('BODY CONTENT');
});
out.w(' ');
});
out.w(' ');
};
}
I started writing some code that I was really hoping would work but it doesn't seem to. I was wondering if self-nested taglibs would be possible because it would be extremely handy for my use case:
{
"tags": {
"mytag": {
"renderer": "./mytag",
"attributes": {
"data": "string"
},
"body-function": "getChildren(__children)",
"import-var": {
"children": "__children"
}
}
}
}
exports.render = function(input, out) {
var children;
if (input.getChildren) {
children = [];
input.getChildren({
addChild: function(child) {
children.push(child);
}
});
}
if (input.children)
input.children.addChild(/* implementation detail */);
else
out.write(/* something utilizing children */);
};
<mytag data="a">
<mytag data="b" />
<mytag data="c" />
</mytag>
So basically my question is whether or not it is somehow possible to include both "body-function" and "import-var" on the same tag and self-nest them. When I try this I get an error that __children is undefined. Is there a way to achieve this currently?
Topics to include:
body-function
import-var
marko-taglib.json
and marko-tag.json
Let's create some logos for Marko!
I'll start things off with a really rough sketch of an idea:
Please feel free to take that idea and make it better or come up with something completely different.
All logos submitted here will be assumed to be licensed as public domain / CC0.
Contributors to the final logo will get credit on the main page and a custom printed T-Shirt with the logo on it!
Hi,
I have a problem with components having their HTML tags closed, incorrectly, by the compiler. For example if I have the following components and html content (shown simplified):
(components/app-header/template.marko)
HTML content: <div class="wrapper"><div class="content">
(components/app-footer/template.marko)
HTML content: </div></div>
index.js
HTML content: <app-header></app-header><div>content here</div><app-footer></app-footer>
I can see the problem. The <app-header>
component's compiled .js file has added the closing 'div' tags automatically, which breaks the layout as the 'wrapper' and 'content' elements are now closed, when they should be left open to contain the main page content.
Is there any setting to prevent this or a different way of laying out the pages?
Thanks,
Pat
I really like the idea of html templating, but I discovered an issue when I tried to use it in my usual dev flow.
As I understand:
now the require-able templates are made possible through a temp file
fs.writeFileSync(tempFile, compiledSrc, {encoding: 'utf8'});
fs.renameSync(tempFile, targetFile);
return require(targetFile);
and although you can bust template cache with unload(templatePath)
, this doesn't clear node's module cache. So every time you require(targetFile)
it will return the same compiled template regardless your meddling with marko's cache.
It's possible to clear node's cache with delete require.cache["absolutePath"]
though, but manually it would be tedious to track every unneeded compiled template.
The problem this makes is during development when a file changes, I want to clear the cache so the engine can re-render the template, or refresh the browser for instance.
I think writing the compiled template to disk should be a feature, or an option, rather than a byproduct of rendering.
Is there a way not to write the compiled template directly to disk, but rather keep it only in memory?
I think it would be useful in development.
Thanks in advance!
Input data:
{
options: [
{
value: 'red',
selected: false
},
{
value: 'green',
selected: true
},
{
value: 'blue',
selected: false
}
]
}
Input Marko template:
<select>
<option value="${option.value}" selected="${option.selected}" for="option in data.options">
${option.value}
</option>
</select>
Output HTML:
<select>
<option value="red">red</option>
<option value="green" selected>green</option>
<option value="blue">blue</option>
</select>
We are getting errors similar to what we see below, it will be great to get the entire stack trace here so we know what line has is the problem.
ERROR r1coltv/src/controllers/dealsHub: { '0': [TypeError: Cannot read property 'left' of undefined] } bad error
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.