
Security News
Meet Socket at Black Hat and DEF CON 2025 in Las Vegas
Meet Socket at Black Hat & DEF CON 2025 for 1:1s, insider security talks at Allegiant Stadium, and a private dinner with top minds in software supply chain security.
dom-render
Advanced tools
npm install dom-render
<!doctype html><html lang="en"><body id="app"></body></html>
const target = document.querySelector('#app');
const data = DomRender.run({name: 'my name is dom-render'}, target);
data.name = 'modify name';
<div>${this.name}</div>
<div>${this.office.addr.first}, ${this.office.addr.last}, ${this.office.addr.street} (${this.office.name})</div>
<div dr="this.office.addr.street">${this.getOfficeFullAddr()}</div>
<div dr-if="true">true</div>
<div dr-if="this.gender==='M'">gender: M</div>
<div dr-for="var i = 0; i < this.friends.length; i++"> friend</div>
<div dr-for-of="this.friends"> ${#it#.name}</div>
<div dr-for-of="$range(10, 20)"><div>${#it#}</div><div>
<div dr-for="var i = 1 ; i <= 9 ; i++" dr-it="i">
${#it#} *
<scope dr-for="var y = 1 ; y <= 9 ; y++" dr-it="y" dr-var="superIt=#it#" dr-strip="true">
#it# = ${var.superIt * #it#}
</scope>
</div>
<div dr-repeat="10"><div>#it#</div></div>
<div dr-repeat="$range(10, 20)"><div>#it#</div></div>
<div dr-repeat="$range(10, 20, 5)"><div>#it#</div></div>
<div dr-repeat="$range('10..5, 2')"><div>#it#</div></div>
<div dr-inner-text="'<b>aa</b> <button dr-event-click=\'alert(1)\'>aa</button>'"> friend</div>
<div dr-inner-html="'<b>aa</b> <button dr-event-click=\'alert(1)\'>aa</button>'"> friend</div>
dr-event-(name)
click: <button dr-event-click="this.name = 'name' + new Date()">click</button> <br>
change: <input type="text" dr-event-change="this.name = $target.value"> <br>
input: <input type="text" dr-event-input="this.name = $target.value"> <br>
keyup: <input type="text" dr-event-keyup="this.name = $target.value"> <br>
...
keydown: <input type="text" dr-event-keydown="this.name = $target.value"><br>
submit: <form dr-event-submit="console.log($event); $event.preventDefault();"><input type="text"> <button type="submit">submit</button></form><br>
dr-window-event-popstate
window-event-popstate: <input type="text" dr-window-event-popstate="alert(this.name)"><br>
dr-event
<input dr-event:bind='eventName1, eventName2' dr-event="console.log('event', $params, $event)" type="text">
dr-value
dr-value-link
dr-value: <input type="text" dr-value="this.office.name"> <br>
dr-value-link: <input type="text" dr-value-link="this.office.addr.street"> <br>
<textarea dr-attr="{rows: this.age/2, cols: this.age}"></textarea>
<div dr-attr="{wow: '123', good: 123444}"></div>
<div dr-attr="['wow=123', 'good=123444']"></div>
<div dr-attr="'wow=123, good=123444'"></div>
<div dr-class="{big: this.age > 50, red: this.age > 50}">
<div dr-class="'big yellow ' + (this.age > 50 ? 'old' : 'young')">
<div dr-class="['small', 'yellow']">
<div dr-style="{fontSize: this.age + 'px'}"> style </div>
<div dr-style="{'font-size': '20px'}"> style</div>
<div dr-style="'font-size: ' + this.age +'px; margin: ' + this.age + 'px'"> style </div>
<div dr-style="['font-size: ' + this.age +'px', 'margin: ' + this.age + 'px']"> style </div>
as-is
<div dr-strip="true"><span>hello</span></div>
to-be
<span>hello</span>
<input dr-on-init="this.onInitElement">
<div dr-before="console.log('process before')" dr-after="console.log('process after')"></div>
<select dr-value-link="this.currentContry" dr-event-change="this.contryChange($event)">
<option dr-for-of="this.languages" dr-value="#it#.key" dr-complete="this.currentContry='defaultValue'">${#it#.title}</option>
</select>
* OnInitRender
- onInitRender(): init render call
new DomRender.run(obj, target, {
scripts: {
concat: function (head: string, tail: string) {
return head + tail;
}
}
});
using script
const data = config.scripts.concat('head', 'tail')
<div>${$scripts.concat('head', 'tail')}</div>
<div dr-if="$scripts.concat('wow', 'good') === 'wowgood'"> is wowgood</div>
export namespace Profile {
export const templat = '<div>aaaaa${this.name}aaaaa </div>';
export const styles = ['p {color: red}', 'div {margin: ${this.margin} + \'px\' }'];
export class Component {
public name = 'default name';
public margin = 5;
public say() {
console.log('say!~')
}
}
}
new DomRender.run(obj, target, {
targetElements: [
RawSet.createComponentTargetElement('my-element', (e, o, r) => new Profile.Component(), Profile.templat, Profile.styles, scripts)
],
});
using component
<my-element dr-on-init="$component.say();"></my-element>
class User {
form = {};
submit() {
const form = (this.form as any)
console.log('submit->', form, form.name, form.age, form.addr);
}
}
<form dr-form="this.form" dr-event-submit="this.submit(); $event.preventDefault();">
name: <input name="name">
age: <input name="age">
addr: <input dr-form:event="input" name="addr">
<button type="submit"> aa</button>
</form>
<div class="row mb-3">
<div class="col">
<span>์์ด๋</span>
<input class="w-100" type="text" name="id" placeholder="์์ด๋" dr-value-link="this.form.id.value" dr-event-blur="this.form.id.valid()" required/>
<span dr-on-init="this.form.id.msgElement" class="d-none"></span>
</div>
</div>
<div class="row mb-3">
<div class="col">
<span>๋น๋ฐ๋ฒํธ</span>
<input class="w-100" type="password" name="id" placeholder="์ซ์, ์๋ฌธ, ํน์๋ฌธ์ ์กฐํฉ ์ต์ 8์~20์" dr-value-link="this.form.password.value" dr-event-blur="this.form.password.valid()" required/>
<span dr-on-init="this.form.password.msgElement" >password valid message section</span>
<input class="w-100" type="password" name="id" placeholder="๋น๋ฐ๋ฒํธ ์ฌ์
๋ ฅ" dr-value-link="this.form.confirmPassword" required/>
<span dr-class="{'d-block': this.form.password != this.form.confirmPassword, 'text-danger': this.form.password != this.form.confirmPassword}">2nd input password valid message section</span>
</div>
</div>
<div class="row mb-3">
<div class="col">
<span>์ด๋ฉ์ผ</span>
<input class="w-100" type="email" name="id" placeholder="์ด๋ฉ์ผ" dr-value-link="this.form.email" required/>
<span class="">2nd input password valid message section</span>
</div>
</div>
</div>
class SignUp {
public form = new class extends Validation {
id = new class extends Validation {
public msgElement!: HTMLElement;
valid(): boolean {
let valid = false;
if (this.length == 0) {
this.msgElement.className = 'd-block text-danger';
this.msgElement.textContent = '์์ด๋๋ฅผ ์
๋ ฅํด์ฃผ์ธ์.';
} else if (this.length < 3 || this.length > 20) {
this.msgElement.className = 'd-block text-danger';
this.msgElement.textContent = '์์ด๋๋ 4๊ธ์ ์ด์ 20์ ๋ฏธ๋ง ์ด์ด์ผ ํฉ๋๋ค.';
} else {
let isExist = false;
if (isExist) {
this.msgElement.className = 'd-block text-danger';
this.msgElement.textContent = '์ด๋ฏธ ์ฌ์ฉ์ค์ธ ์์ด๋์
๋๋ค. ๋ค๋ฅธ ์์ด๋๋ฅผ ์ด์ฉํด์ฃผ์ธ์.';
} else {
this.msgElement.className = 'd-block text-success';
this.msgElement.textContent = '์ฌ์ฉ ๊ฐ๋ฅํ ์์ด๋์
๋๋ค.';
valid = true;
}
}
return valid;
}
}();
password = new class extends Validation {
public msgElement!: HTMLElement;
valid(): boolean {
let valid = false;
let regExp = /^.*(?=.)(?=.*[0-9])(?=.*[a-zA-Z]).*$/;
const ERROR_REQUIRE_PW = '๋น๋ฐ๋ฒํธ๋ฅผ ์
๋ ฅํด์ฃผ์ธ์.';
const ERROR_PW_LENGTH = '๋น๋ฐ๋ฒํธ๋ 8๊ธ์~20๊ธ์๋ก ์ด๋ฃจ์ด์ ธ์ผ ํฉ๋๋ค.';
const ERROR_PW_REGEXP = '๋น๋ฐ๋ฒํธ๋ ์ซ์, ์๋ฌธ, ํน์๋ฌธ์ ์กฐํฉ์ผ๋ก ์ด๋ฃจ์ด์ ธ์ผ ํฉ๋๋ค.';
const SUCCESS_AVAILABLE_USER_PW = '์ฌ์ฉ ๊ฐ๋ฅํ ๋น๋ฐ๋ฒํธ์
๋๋ค.';
if (this.length == 0) {
this.msgElement.className = 'd-block text-danger';
this.msgElement.textContent = ERROR_REQUIRE_PW;
} else if (this.length < 8 || this.length > 20) {
this.msgElement.className = 'd-block text-danger';
this.msgElement.textContent = ERROR_PW_LENGTH;
} else {
if (regExp.test(this.value)) {
this.msgElement.className = 'd-block text-success';
this.msgElement.textContent = SUCCESS_AVAILABLE_USER_PW;
valid = true;
} else {
this.msgElement.className = 'd-block text-danger';
this.msgElement.textContent = ERROR_PW_REGEXP;
}
}
return valid;
}
}();
confirmPassword = new class extends Validation {
value = '';
valid(): boolean {
return true;
}
}();
email = new class extends Validation {
value = '';
valid(): boolean {
return true;
}
}();
valid() {
return this.childValid()
}
}();
}
form = new class extends Validation {
id = new class extends Validation {
valid(): boolean {
return false;
}
}()
valid(): boolean {
return false;
}
}();
console.log(form.id.value)
<form dr-form="this.form" dr-event-submit="this.submit(); $event.preventDefault();">
<input name="id"> <!-- id value -->
<input name=""> <!-- root value -->
<button type="submit"> submit</button>
</form>
OnBeforeReturnSet
export interface OnBeforeReturnSet {
onBeforeReturnSet(name: string, value: any, fullPath?: string[]): void;
}
OnBeforeReturnGet
export interface OnBeforeReturnGet {
onBeforeReturnGet(name: string, value: any, fullPath?: string[]): void;
}
using detect
{
name: 'dom-render'
onBeforeReturnSet: (name: string, value: any, fullpath: string[]) => {
console.log('set name-->', name, value, fullpath);
}
onBeforeReturnGet: (name: string, value: any, fullpath: string[]) => {
console.log('get name-->', name, value, fullpath);
}
}
exclude detect property: Config
all internal variables are managed by proxy. (DomRenderProxy)
exclude detect property: Config
Code base
// frezz
{name : Object.freeze({...})}
// Shield Object type: {[k: string]: any}
{name : new Shield()}
// DomRenderProxy Final
{name : DomRenderProxy.final({...})}
export type TargetElement = {
_name: string,
template?: string,
styles?: string[],
callBack: (target: Element, obj: any, rawSet: RawSet) => DocumentFragment,
complete?: (target: Element, obj: any, rawSet: RawSet) => void
};
export type TargetAttr = {
name: string,
callBack: (target: Element, attrValue: string, obj: any, rawSet: RawSet) => DocumentFragment,
complete?: (target: Element, attrValue: string, obj: any, rawSet: RawSet) => void
};
export interface Config {
targetElements?: TargetElement[];
targetAttrs?: TargetAttr[];
onElementInit?: (name: string, obj: any, rawSet: RawSet) => void;
onAttrInit?: (name: string, attrValue: string, obj: any, rawSet: RawSet) => void;
proxyExcludeTyps?: ConstructorType<any>[];
proxyExcludeOnBeforeReturnSets?: string[];
proxyExcludeOnBeforeReturnGets?: string[];
scripts?: { [n: string]: any };
applyEvents?: { attrName: string, callBack: (elements: Element, attrValue: string, obj: any) => void }[];
}
FAQs
html view template engine
We found that dom-render demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago.ย It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Meet Socket at Black Hat & DEF CON 2025 for 1:1s, insider security talks at Allegiant Stadium, and a private dinner with top minds in software supply chain security.
Security News
CAI is a new open source AI framework that automates penetration testing tasks like scanning and exploitation up to 3,600ร faster than humans.
Security News
Deno 2.4 brings back bundling, improves dependency updates and telemetry, and makes the runtime more practical for real-world JavaScript projects.