On the Koji platform, you can develop JavaScript web applications that can be customized without coding.Instead, non-technical users can use Visual Customization Controls (VCCs) to quickly edit elements of the application, such as images, text, and sounds.
In this starter guide, you will start with an existing web application on Koji, called a “template,” and add the ability to customize, or “remix,” it.You will use the Koji editor and an npm package from Koji to define the customizable elements.Then, you will publish your application as a new template so that Koji users can create their own customized versions of it.
Remixing the starter scaffold
If you haven’t already, create an account at withkoji.com.
Open a starter scaffold that implements basic elements of your favorite framework.
React
Vanilla JS
Angular
Svelte
React
React scaffold
Vanilla JS
Vanilla JS scaffold
Angular
Angular scaffold
Svelte
Svelte scaffold
Click the Koji button in the top right, and then click Advanced > Fork.
This action creates a clone of the starter scaffold and opens it in the Koji editor.
Explore the template and the Koji editor.
In the right pane, you can see a live preview of the template.
In the left pane, you can click Source Code to expand the file browser.From here, you can open and edit your project files in the editor.
At the bottom, you can expand a set of terminal tabs.These tabs enable you to run the template locally from inside the editor and to execute other terminal functions, such as adding packages and committing changes.
Note
If you make changes to your project’s structure (by adding npm packages, for example), you might need to cancel the running process and restart the development server in the frontend
terminal.
Installing the @withkoji/vcc package
The @withkoji/vcc package allows your template to access dynamic values that are stored in customization files.It also allows you to expose VCCs so that a user can change the customizable items in your template.Finally, it provides a watcher function that allows you to monitor changes to customization files and perform a real-time set of the dynamic values stored in the customization files.
Open the
frontend
terminal, and cancel the running process (for example, press Ctrl+C).Install the latest version of the package.
npm install --save @withkoji/vcc
Reconfigure the
package.json
file to run the watcher concurrently with your development server.You can use a package like npm-run-all.For example:Install npm-run-all.
npm install --save-dev npm-run-all
Modify the
package.json
file.React
Vanilla JS
Angular
Svelte
React
{ "scripts": { ... "start": "npm-run-all -p watch start:server", "watch": "koji-vcc watch", "start:server": "webpack-dev-server --config ./.internals/webpack.development.js --inline --hot" }}
Vanilla JS
{ "scripts": { ... "start": "npm-run-all -p watch start:server", "watch": "koji-vcc watch", "start:server": "webpack-dev-server --config ./.internals/webpack.development.js --inline --hot" }}
Angular
"scripts": { ... "start": "npm-run-all -p watch start:server", "watch": "koji-vcc watch", "start:server": "cross-env NODE_ENV=development ng serve --host 0.0.0.0 --port 4200 --disableHostCheck=true", ...}
Svelte
"scripts": { "start": "npm-run-all -p watch start:server", "watch": "koji-vcc watch", "start:server": "parcel src/index.html -p 8080", ...}
Warning
Make sure to replace the value of "start:server"
with the"start"
command for your project and remove theprestart
command, if there is one.Restart the process to reflect the new changes.
npm start
Creating a customization file
A customization file is a JSON file that defines the names and types of the customizable values in a template, so that Koji can display the appropriate VCCs for remixers.
In the
.koji/customization
folder of your project, create a new JSON file.In the file browser, click the plus (+) next to the
.koji/customization
folder, and click New file.Enter a name for the file.For example:
settings.json
.
Paste the following code into your
settings.json
file.This code defines a scope and the customizable values within that scope.
{ "settings": { "title": "Hello World!"},"@@editor": [ { "key": "settings", "name": "App settings", "icon": "⚙️", "source": "settings.json", "fields": [ { "key": "title", "name": "App title", "type": "text" } ] } ] }
Press Ctrl-S to save the file.
A new item appears in the VCC Explorer section of the left pane.
Click the item in the VCC Explorer section to display the associated VCC in the editor.
In this example, the file stores one customizable value (
settings.title
), and Koji displays a text VCC to collect this value from a remixer.
Accessing the values stored in a customization file
To access a value from a JSON customization file within a template, you use a getter from the @withkoji/vcc package.Then, update the template to use dynamic values, instead of hard-coded values.
From the left pane of the editor, open the file that contains the template logic.
React
Vanilla JS
Angular
Svelte
React
frontend/common/App.js
Vanilla JS
frontend/index.js
Angular
frontend/src/app/app.component.ts
Svelte
src/App.svelte
At the top of the file, import the package.
React
Vanilla JS
Angular
Svelte
React
import { InstantRemixing } from '@withkoji/vcc';
Vanilla JS
import { InstantRemixing } from '@withkoji/vcc';
Angular
import { InstantRemixing } from '@withkoji/vcc';
Svelte
<script> import { InstantRemixing } from '@withkoji/vcc';</script>
Create a new instance of the
InstantRemixing
class to use in the template and alert Koji that instant remixing is ready to use.React
Vanilla JS
Angular
Svelte
Example 1. React
In the React component, add the
componentDidMount
method.componentDidMount() { this.instantRemixing = new InstantRemixing(); console.log('instantRemixing', this.instantRemixing); // Confirm w/log // Alert Koji we are ready to use instantRemixing this.instantRemixing.ready();}
Example 2. Vanilla JS
Add this code above the
render
function definition.var instantRemixing = new InstantRemixing();// Alert Koji we are ready to use instantRemixinginstantRemixing.ready();
Example 3. Angular
In the Angular component, add a new property and update the
ngOnInit
method.export class AppComponent implements OnInit { instantRemixing = null; ngOnInit() { this.instantRemixing = new InstantRemixing(); console.log('instantRemixing', this.instantRemixing); // Confirm w/log // Alert Koji we are ready to use instantRemixing this.instantRemixing.ready(); }}
Example 4. Svelte
Add the
onMount
method.<script> import { onMount } from 'svelte'; import { InstantRemixing } from '@withkoji/vcc'; let instantRemixing; let title; onMount(() => { instantRemixing = new InstantRemixing(); // Alert Koji we are ready to use instantRemixing instantRemixing.ready(); });</script>
Update the contents of the
h1
element to use the dynamictitle
value.React
Vanilla JS
Angular
Svelte
Example 5. React
Create a state to handle updates to the title value.
class App extends React.Component { state = { title: '', }; ... render() { return ( <Container> <h1>{this.state.title}</h1> <Image src={'https://images.koji-cdn.com/d9c6b38e-08c4-4faf-ae8e-01082c41a0fb/3f83q-9634d620e97345a6b250ca2feb7e5a2e.png'} /> </Container> ); }}
Example 6. Vanilla JS
Add an
id
attribute to access the element more easily in the next step.// render appconst render = () => { document.body.innerHTML = ` <h1 id="title">${title}</h1> <img id="logo" src="https://images.koji-cdn.com/e62ec06b-01be-4183-a7c0-ee6e8950f398/t5ues-600pxJavaScriptlogo.png"/> `;};
Example 8. Angular
app.component.ts
app.component.html
Example 7. app.component.ts
Add a property to handle updates to the title value, and then update
app.component.html
.export class AppComponent implements OnInit { instantRemixing = null; title = ''; ...}
app.component.html
<div class="container"> <h1>{{title}}</h1> <img class="image" src="https://images.koji-cdn.com/cf19e146-554d-459e-96a1-b36b71eda51e/userData/gi3e2wscdw-b8ae90b11dbb4339a93af61c9e0a2100.png" /></div>
Svelte
<h1>{title}</h1>
Use the getter function from
instantRemixing
to get the default value from the customization file.The getter accepts an array (
[scope, key]
) that maps to the scope (settings
) and key (title
) from the JSON customization file.React
Vanilla JS
Angular
Svelte
React
componentDidMount() { this.instantRemixing = new InstantRemixing(); console.log('instantRemixing', this.instantRemixing); // Confirm w/log // Set the default value this.setState({ title: this.instantRemixing.get(['settings', 'title']) }); // Alert Koji we are ready to use instantRemixing this.instantRemixing.ready();}
Example 9. Vanilla JS
Create a variable to handle updates to the title value.
var title = instantRemixing.get(['settings', 'title']);
Angular
ngOnInit() { this.instantRemixing = new InstantRemixing(); console.log('instantRemixing', this.instantRemixing); // Confirm w/log // Set the default value this.title = this.instantRemixing.get(['settings', 'title']); // Alert Koji we are ready to use instantRemixing this.instantRemixing.ready();}
Svelte
onMount(() => { instantRemixing = new InstantRemixing(); // Set the default value title = instantRemixing.get(['settings', 'title']); // Alert Koji we are ready to use instantRemixing instantRemixing.ready();});
Reacting to updated values
When a remixer enters a new value, the template must update automatically to reflect the change.
Set up a listener to monitor for changes to the template value.
React
Vanilla JS
Angular
Svelte
Example 10. React
Add the listener in the
componentDidMount
method.componentDidMount() { this.instantRemixing = new InstantRemixing(); console.log('instantRemixing', this.instantRemixing); // Confirm w/log // Set the default value this.setState({ title: this.instantRemixing.get(['settings', 'title']) }); // Set up a listener to update title value this.instantRemixing.onValueChanged((path, newValue) => { if (path[0] && path[1] && path[0] === 'settings' && path[1] === 'title') { this.setState({ title: newValue }); } }); // Alert Koji we are ready to use instantRemixing this.instantRemixing.ready();}
Example 11. Vanilla JS
Add the listener below the
render
function call.// Add a listener to the on change event of instant remixing to update the titleinstantRemixing.onValueChanged((path, newValue) => { if (path[0] && path[0] === 'settings' && path[1] && path[1] === 'title') { let titleElement = document.getElementById('title'); titleElement.textContent = newValue; }});
Example 12. Angular
Add the listener in the
ngOnInit
method.ngOnInit() { this.instantRemixing = new InstantRemixing(); console.log('instantRemixing', this.instantRemixing); // Confirm w/log // Set the default value this.title = this.instantRemixing.get(['settings', 'title']); // Set up a listener to update title value this.instantRemixing.onValueChanged((path, newValue) => { if (path[0] && path[1] && path[0] === 'settings' && path[1] === 'title') { this.title = newValue; } }); // Alert Koji we are ready to use instantRemixing this.instantRemixing.ready();}
Example 13. Svelte
Add the listener in the
onMount
method.onMount(() => { instantRemixing = new InstantRemixing(); // Set the default value title = instantRemixing.get(['settings', 'title']); // Set up a listener to update title value instantRemixing.onValueChanged((path, newValue) => { if (path[0] && path[1] && path[0] === 'settings' && path[1] === 'title') { title = newValue; } }); // Alert Koji we are ready to use instantRemixing instantRemixing.ready();});
Tip
Make sure to set up your listeners before calling the ready
method.The Koji platform will queue any messages before theready
call to wait for the listeners to be ready.
Testing the current state of the template
At this point, the template should be configured to use the default value from the customization file and to react to value changes that are made from VCCs.To test this configuration, you can use the built-in VCC and live preview in the Koji editor.
In the top right of the Live Preview pane, click Refresh to make sure you are seeing the latest version.
From the left pane of the editor, click VCC Explorer > App Settings to open the VCC for the
settings.json
customization file.In the VCC, update the value in the App title field.
The preview window should reflect your update automatically.
Determining the current view of the template
The template must display differently and expose different click handlers depending on whether a user is viewing or customizing the template.In this example, you will add styles to show that the h1
element is editable and a click handler to expose a VCC when a user is customizing the template.
Create a property (
isRemixing
) to track the current view state, if needed.React
Vanilla JS
Angular
Svelte
React
state = { isRemixing: false, title: '',};
Vanilla JS
Not needed
Angular
instantRemixing = null;title = '';isRemixing = false;
Svelte
let isRemixing;
Add a listener that monitors the template for view changes between remixing and viewing.
React
Vanilla JS
Angular
Svelte
Example 14. React
In the
setState
function, set the default value forthis.instantRemixing.isRemixing
, and then add the listener to maintain it as a source of truth for the current view.componentDidMount() { this.instantRemixing = new InstantRemixing(); console.log('instantRemixing', this.instantRemixing); // Confirm w/log // Set the default value for title and isRemixing state this.setState({ isRemixing: this.instantRemixing.isRemixing, title: this.instantRemixing.get(['settings', 'title']) }); // Set up a listener to update title value this.instantRemixing.onValueChanged((path, newValue) => { if (path[0] && path[1] && path[0] === 'settings' && path[1] === 'title') { this.setState({ title: newValue }); } }); // Toggle the isRemixing state based on the listener this.instantRemixing.onSetRemixing((isRemixing) => { this.setState({ isRemixing }); }); // Alert Koji we are ready to use instantRemixing this.instantRemixing.ready();}
Example 15. Vanilla JS
// Add a listener to handle state changes between remixing and notinstantRemixing.onSetRemixing((isRemixing) => { if (isRemixing) { startRemix(); } else { stopRemix(); }});
Note
You will add implementations of startRemix
andstopRemix
in subsequent steps.Angular
ngOnInit() { this.instantRemixing = new InstantRemixing(); console.log('instantRemixing', this.instantRemixing); // Confirm w/log // Set the default value for title and isRemixing state this.isRemixing = this.instantRemixing.isRemixing; this.title = this.instantRemixing.get(['settings', 'title']); // Set up a listener to update title value this.instantRemixing.onValueChanged((path, newValue) => { if (path[0] && path[1] && path[0] === 'settings' && path[1] === 'title') { this.title = newValue; } }); // Toggle the isRemixing state based on the listener this.instantRemixing.onSetRemixing((isRemixing) => { this.isRemixing = isRemixing; }); // Alert Koji we are ready to use instantRemixing this.instantRemixing.ready();}
Svelte
onMount(() => { instantRemixing = new InstantRemixing(); // Set the default value for title and isRemixing state isRemixing = instantRemixing.isRemixing; title = instantRemixing.get(['settings', 'title']); // Set up a listener to update title value instantRemixing.onValueChanged((path, newValue) => { if (path[0] && path[1] && path[0] === 'settings' && path[1] === 'title') { title = newValue; } }); // Toggle the isRemixing state based on the listener instantRemixing.onSetRemixing((isRemixingTrue) => { isRemixing = isRemixingTrue; }); // Alert Koji we are ready to use instantRemixing instantRemixing.ready();});
Exposing the VCC
The template must expose a way for a remixer to open the VCC when customizing it.
Add a click handler that opens the VCC when the remixer clicks the title (
h1
element).React
Vanilla JS
Angular
Svelte
React
handleClick = () => { // Conditionally handle the click, only if the template is being remixed if (this.state.isRemixing) { this.instantRemixing.onPresentControl(['settings', 'title']); }};render() { return ( <Container> <h1 onClick={this.handleClick}>{this.state.title}</h1> <Image src={'https://images.koji-cdn.com/d9c6b38e-08c4-4faf-ae8e-01082c41a0fb/3f83q-9634d620e97345a6b250ca2feb7e5a2e.png'} /> </Container> );}
Vanilla JS
// Add click event listener to expose title VCCdocument.addEventListener('click', function (event) { if (!event.target.matches('#title')) return; event.preventDefault(); instantRemixing.onPresentControl(['settings', 'title']);});
Example 16. Angular
app.component.ts
app.component.html
app.component.ts
handleClick = () => { // Conditionally handle the click, only if the template is being remixed if (this.isRemixing) { this.instantRemixing.onPresentControl(['settings', 'title']); }};
app.component.html
<div class="container"> <h1 (click)="handleClick()">{{title}}</h1> <img class="image" src="https://images.koji-cdn.com/cf19e146-554d-459e-96a1-b36b71eda51e/userData/gi3e2wscdw-b8ae90b11dbb4339a93af61c9e0a2100.png" /></div>
Svelte
function editText() { // Conditionally handle the click, only if the template is being remixed if (isRemixing) { instantRemixing.onPresentControl(['settings', 'title']); }};...<h1 on:click={editText}>{title}</h1>
Testing the expose function
To test whether the expose function is working, you can use the Editing tab of the Live Preview pane.This feature enables you to test the template as if it were published on Koji.
In the Live Preview pane, click Editing to switch to the template editing mode.
Click the title in the preview.
The VCC should open automatically and allow for text input.If this test works correctly, the VCC should be exposed correctly to the remixer in your published template.
Styling the customizable item
To indicate that an item is “editable,” you can add a conditional visual effect that is displayed when the template is being customized.In this example, you’ll add a CSS style class for editable items and then apply the class to the h1
when a user is customizing the template.
From the left pane of the editor, open the following file.
React
Vanilla JS
Angular
Svelte
React
frontend/common/index.html
Vanilla JS
frontend/style.css
Angular
frontend/src/app/app.component.scss
Svelte
src/App.svelte
Add the following style definition.
React
Vanilla JS
Angular
Svelte
React
<style> .active { background-color: rgba(255, 255, 255, 0.4); padding: 18px; border-width: 1px; border-style: solid; border-color: rgb(255, 255, 255); border-image: initial; border-radius: 4px; }</style>
Vanilla JS
.edit { border: 2px dashed grey;}
Angular
.active { background-color: rgba(255, 255, 255, 0.4); padding: 18px; border-width: 1px; border-style: solid; border-color: rgb(255, 255, 255); border-image: initial; border-radius: 4px;}
Svelte
<style> .remixing { background-color: rgba(255, 255, 255, 0.4); padding: 18px; border-width: 1px; border-style: solid; border-color: rgb(255, 255, 255); border-image: initial; border-radius: 4px; }</style>
Update the
h1
element with dynamic styling.React
Vanilla JS
Angular
Svelte
Example 17. React
In the
App.js
file, use a dynamicclassName
.<h1 className={this.state.isRemixing ? 'active' : ''} onClick={this.handleClick} > {this.state.title}</h1>
Example 18. Vanilla JS
Add implementations of
startRemix
andstopRemix
that modify the class name of theh1
element, for simplicity in this tutorial.// Modify elements to display state for remixingconst startRemix = () => { let titleElement = document.getElementById('title'); titleElement.classList.add('edit');};// Modify elements to display state for previewingconst stopRemix = () => { let titleElement = document.getElementById('title'); titleElement.classList.remove('edit');};
Example 19. Angular
In the
app.component.html
file, use a dynamicclass
.<h1 class="{{isRemixing ? 'active' : ''}}" (click)="handleClick()"> {{title}}</h1>
Svelte
<h1 class={isRemixing ? 'remixing' : ''} on:click={editText}> {title}</h1>
To test the dynamic styling, you can toggle the live preview between the Editing and Preview modes.
In Editing mode, the “editable” styles should be visible, and the click handler should open the VCC, as expected.
In Preview mode, the “editable” styles should not be visible, and nothing should happen when clicking the
h1
element.
Making the template “feed-aware”
Koji uses a feed to enable users to browse available templates.As with traditional social feeds, items move from off screen or out of focus, into the main window inside the feed.To ensure the template is displayed correctly in the Koji feed, you use the FeedSdk from the @withkoji/vcc package to set the template state and handle transitions between on and off screen and in and out of focus.
Import the
FeedSdk
from the @withkoji/vcc package.import { FeedSdk, InstantRemixing } from '@withkoji/vcc';
Add the following code to display the template in the feed.
React
Vanilla JS
Angular
Svelte
Example 20. React
Add this code at the end of the
componentDidMount
method.this.feed = new FeedSdk();this.feed.load();
Example 21. Vanilla JS
Add this code below the
render
function call.var feed = new FeedSdk();feed.load();
Example 22. Angular
Add a new property, and add code at the end of the
ngOnInit
method.export class AppComponent implements OnInit { ... feed = null; ngOnInit() { ... this.feed = new FeedSdk(); this.feed.load(); }}
Example 23. Svelte
Add this code at the end of the
onMount
method.let feed = new FeedSdk();feed.load();
This code creates an instance of the feed and calls a load function to indicate that the template is ready to be displayed in the feed, which is all that is required when the template does not use autoplay.
Note
If you plan to develop templates that autoplay when focused in the feed, you can use the onPlaybackStateChanged
listener to monitor for real-time updates as the template enters and leaves focus in the feed, similar to how this example usesonSetRemixing
.
Adding entitlements for the Koji profiler
When you publish the template, it is submitted into a queue for profiling.The Koji profiler checks for errors and generates metadata about the application.If the template is error-free, the profiler enables additional platform features for your template, including the instant remix option and inclusion in the feed.To prepare your template to be profiled correctly, you must add entitlements for some of these features.
In the
.koji/project
folder, create anentitlements.json
file with the following code:{ "entitlements": { "InstantRemixing": true, "FeedEvents": true }}
This code indicates that the template supports remixes and is ready to be listed in the feed.
Publishing the template
At this point, the template is ready to be published.
To preview the template on the staging server before you publish it, you can click the remote staging button
in the preview pane to open the preview in a new tab.
To preview the template on a mobile device, you can click the QR code button
in the preview pane to display the QR code, then scan the code with your mobile device.
In the upper left of the editor, click Publish Now to open the publish settings.
Give your template a unique name and add a description.
Note
The permalink URL to your template is based on the name when you first publish it, so be sure to enter the name you want to use going forward.You can republish it to update any template functionality and settings, but the link remains the same. Click Publish New Version.
A message appears to indicate that the publishing process has started.When publishing is completed, a link appears in the message.
Click the link to view and test your live template.
The template might be published before profiling is completed.Therefore, you might need to wait longer before testing features that require profiling, such as inclusion in the feed or the ability to instantly remix the template.To see the results of the most recent profiling, from your live template, click the Koji button, and then click More > Developer Tools.Select the attributes you want to see, such as Content Audit or Entitlements.
If an error message appears when you open the link after profiling is completed, you can review the steps in this guide to fix it.
Completed samples and next steps
In this guide, you learned how to add basic customizable elements to a template and then publish it on Koji.
To troubleshoot any issues with your template, you can compare your code to this completed sample of the logic described in this guide.
React
Vanilla JS
Angular
Svelte
Example 24. React
frontend/common/App.js
import React from 'react';import styled from 'styled-components';import { FeedSdk, InstantRemixing } from '@withkoji/vcc';const Container = styled.div` background-color: #395b88; min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center; font-size: calc(10px + 2vmin); text-align: center; color: #fcfcfc;`;const Image = styled.img` max-width: 50vmin; max-height: 50vmin;`;class App extends React.Component { state = { isRemixing: false, title: '', }; componentDidMount() { this.instantRemixing = new InstantRemixing(); console.log('instantRemixing', this.instantRemixing); // Confirm w/log // Set the default value this.setState({ isRemixing: this.instantRemixing.isRemixing, title: this.instantRemixing.get(['settings', 'title']) }); // Set up a listener to update title value this.instantRemixing.onValueChanged((path, newValue) => { if (path[0] && path[1] && path[0] === 'settings' && path[1] === 'title') { this.setState({ title: newValue }); } }); // Toggle the isRemixing state based on the listener this.instantRemixing.onSetRemixing((isRemixing) => { this.setState({ isRemixing }); }); // Alert Koji we are ready to use instantRemixing this.instantRemixing.ready(); this.feed = new FeedSdk(); this.feed.load(); } handleClick = () => { // Conditionally handle the click, only if the template is being remixed if (this.state.isRemixing) { this.instantRemixing.onPresentControl(['settings', 'title']); } }; render() { return ( <Container> <h1 className={this.state.isRemixing ? 'active' : ''} onClick={this.handleClick} > {this.state.title} </h1> <Image src={'https://images.koji-cdn.com/d9c6b38e-08c4-4faf-ae8e-01082c41a0fb/3f83q-9634d620e97345a6b250ca2feb7e5a2e.png'} /> </Container> ); }}export default App;
Example 25. Vanilla JS
frontend/index.js
import './styles.css';import { FeedSdk, InstantRemixing } from '@withkoji/vcc';var instantRemixing = new InstantRemixing();var title = instantRemixing.get(['settings', 'title']);// render appconst render = () => { document.body.innerHTML = ` <h1 id="title">${title}</h1> <img id="logo" src="https://images.koji-cdn.com/e62ec06b-01be-4183-a7c0-ee6e8950f398/t5ues-600pxJavaScriptlogo.png"/> `;};// Modify elements to display state for remixingconst startRemix = () => { let titleElement = document.getElementById('title'); titleElement.classList.add('edit');};// Modify elements to display state for previewingconst stopRemix = () => { let titleElement = document.getElementById('title'); titleElement.classList.remove('edit');};var feed = new FeedSdk();feed.load();// Add a listener to the on change event of instant remixing to update the titleinstantRemixing.onValueChanged((path, newValue) => { if (path[0] && path[0] === 'settings' && path[1] && path[1] === 'title') { let titleElement = document.getElementById('title'); titleElement.textContent = newValue; }});// Add a listener to handle state changes between remixing and notinstantRemixing.onSetRemixing((isRemixing) => { if (isRemixing) { startRemix(); } else { stopRemix(); }});// Add click event listener to expose title VCCdocument.addEventListener('click', function (event) { if (!event.target.matches('#title')) return; event.preventDefault(); instantRemixing.onPresentControl(['settings', 'title']);});// Alert Koji we are ready to use instantRemixinginstantRemixing.ready();// renderrender();
Example 26. Angular
frontend/src/app/app.component.ts
import { Component, OnInit } from '@angular/core';import { FeedSdk, InstantRemixing } from '@withkoji/vcc';@Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'],})export class AppComponent implements OnInit { instantRemixing = null; title = ''; isRemixing = false; feed = null; ngOnInit() { this.instantRemixing = new InstantRemixing(); console.log('instantRemixing', this.instantRemixing); // Confirm w/log // Set the default value for title and isRemixing state this.isRemixing = this.instantRemixing.isRemixing; this.title = this.instantRemixing.get(['settings', 'title']); // Set up a listener to update title value this.instantRemixing.onValueChanged((path, newValue) => { if (path[0] && path[1] && path[0] === 'settings' && path[1] === 'title') { this.title = newValue; } }); // Toggle the isRemixing state based on the listener this.instantRemixing.onSetRemixing((isRemixing) => { this.isRemixing = isRemixing; }); // Alert Koji we are ready to use instantRemixing this.instantRemixing.ready(); this.feed = new FeedSdk(); this.feed.load(); } handleClick = () => { // Conditionally handle the click, only if the template is being remixed if (this.isRemixing) { this.instantRemixing.onPresentControl(['settings', 'title']); } };}
Example 27. Svelte
src/App.svelte
<script> import { onMount } from 'svelte'; import { FeedSdk, InstantRemixing } from '@withkoji/vcc'; let instantRemixing; let title; let isRemixing; onMount(() => { instantRemixing = new InstantRemixing(); // Set the default value for title and isRemixing state isRemixing = instantRemixing.isRemixing; title = instantRemixing.get(['settings', 'title']); // Set up a listener to update title value instantRemixing.onValueChanged((path, newValue) => { if (path[0] && path[1] && path[0] === 'settings' && path[1] === 'title') { title = newValue; } }); // Toggle the isRemixing state based on the listener instantRemixing.onSetRemixing((isRemixingTrue) => { isRemixing = isRemixingTrue; }); // Alert Koji we are ready to use instantRemixing instantRemixing.ready(); let feed = new FeedSdk(); feed.load(); }); function editText() { // Conditionally handle the click, only if the template is being remixed if (isRemixing) { instantRemixing.onPresentControl(['settings', 'title']); } };</script><style> .remixing { background-color: rgba(255, 255, 255, 0.4); padding: 18px; border-width: 1px; border-style: solid; border-color: rgb(255, 255, 255); border-image: initial; border-radius: 4px; }</style><div class="image" style='background-image: url("https://images.koji-cdn.com/43188147-b060-443f-b76a-9fddd4b93f38/p6a4a-a6471bdde6154e5ab793a13c5dfcd81c.png?optimize=50");'></div><h1 class={isRemixing ? 'remixing' : ''} on:click={editText}> {title}</h1>
To continue working on this project and learn how to create a complete and compelling Koji template, see start-guide-2.html.