diff --git a/defineRenderer.js b/defineRenderer.js new file mode 100644 index 000000000..89b99ef1a --- /dev/null +++ b/defineRenderer.js @@ -0,0 +1,48 @@ +var marko = require('./'); +var createRenderFunc = require('raptor-renderer').createRenderFunc; + +function defineRenderer(def) { + var template = def.template; + var getTemplateData = def.getTemplateData; + var renderer = def.renderer; + + var loadedTemplate; + + + if (!renderer) { + // Create a renderer function that takes care of translating + // the input properties to a view state. Also, this renderer + // takes care of re-using existing widgets. + renderer = function renderer(input, out) { + var newProps = input; + + if (!newProps) { + // Make sure we always have a non-null input object + newProps = {}; + } + + if (!loadedTemplate) { + // Lazily load the template on first render to avoid potential problems + // with circular dependencies + loadedTemplate = template.render ? template : marko.load(template); + } + + // Use getTemplateData(state, props, out) to get the template + // data. If that method is not provided then just use the + // the state (if provided) or the input data. + var templateData = getTemplateData ? + getTemplateData(newProps, out) : + newProps; + + // Render the template associated with the component using the final template + // data that we constructed + loadedTemplate.render(templateData, out); + }; + } + + renderer.render = createRenderFunc(renderer); + + return renderer; +} + +module.exports = defineRenderer; \ No newline at end of file diff --git a/docs/javascript-api.md b/docs/javascript-api.md index 15190dbe0..6fdcd5a11 100644 --- a/docs/javascript-api.md +++ b/docs/javascript-api.md @@ -251,4 +251,46 @@ Default options: */ assumeUpToDate: NODE_ENV == null ? false : (NODE_ENV !== 'development' && NODE_ENV !== 'dev') }; -``` \ No newline at end of file +``` + +# require('marko/defineRenderer') + +Utility module for building a UI component with both a `renderer(input, out)` (for use as a Marko custom tag renderer) a `render(input)` method (for rendering the UI component and inserting the HTML in the DOM): + + +_src/components/app-hello/index.js_ + +```javascript +var defineRenderer = require('marko/defineRenderer'); + +module.exports = defineRenderer({ + template: require('./template.marko'), + getTemplateData: function(input) { + var firstName = input.firstName; + var lastName = input.lastName; + + return { + fullName: firstName + ' ' + lastName + }; + } +}) +``` + +The UI component can be used as a custom tag: + +```xml + +``` + +And it can also be rendered and inserted into the DOM: + +```javascript +require('./src/components/app-hello') + .render({ + firstName: 'John', + lastName: 'Doe' + }) + .appendTo(document.body); +``` + +The return value of `render()` will be a [RenderResult](https://github.com/raptorjs/raptor-renderer#renderresult) instance. \ No newline at end of file diff --git a/package.json b/package.json index ea575cafb..69f9fb0af 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "raptor-polyfill": "^1.0.0", "raptor-promises": "^1.0.1", "raptor-regexp": "^1.0.0", + "raptor-renderer": "^1.4.4", "raptor-strings": "^1.0.0", "raptor-util": "^1.0.0", "resolve-from": "^1.0.0", diff --git a/test/autotests/api/defineRenderer/template.marko b/test/autotests/api/defineRenderer/template.marko new file mode 100644 index 000000000..47279a6b6 --- /dev/null +++ b/test/autotests/api/defineRenderer/template.marko @@ -0,0 +1,3 @@ +
+ Hello ${data.fullName}! +
\ No newline at end of file diff --git a/test/autotests/api/defineRenderer/test.js b/test/autotests/api/defineRenderer/test.js new file mode 100644 index 000000000..67208cf17 --- /dev/null +++ b/test/autotests/api/defineRenderer/test.js @@ -0,0 +1,16 @@ +exports.check = function(marko, markoCompiler, expect, done) { + + var defineRenderer = require('../../../../defineRenderer'); + var renderer = defineRenderer({ + template: require('./template.marko'), + getTemplateData: function(input) { + return { + fullName: input.firstName + ' ' + input.lastName + }; + } + }); + + var renderResult = renderer.render({ firstName: 'John', lastName: 'Doe' }); + expect(renderResult.html).to.equal('
Hello John Doe!
'); + done(); +}; \ No newline at end of file