Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create Ractive's subcomponents dynamically and change them programmatically

I can instantiate (sub)components manually using tags, but I don't know how to do it dynamically, or, how to insert and remove different components in the same area using tags.

Today I instantiate each (sub)component this way:

Ractive.load( '/templates/global/example.html' ).then( function ( Example )
{
       ractive.components.example = new Example( { el : 'aside' } );
});

But the new (sub)component can't see the data of it's parent instance in mustache, only his own data.

like image 652
Paulo Coghi Avatar asked Jun 26 '15 14:06

Paulo Coghi


People also ask

How do I use a dynamic component with a prop?

Inside the DynamicComponent we created a SelectUser variable and returned it, so that if we pass usera as a prop UserA component is rendered or if we pass userb as a prop UserB component is rendered on the screen. Let’s use our dynamic component now by importing it.

How many components are there in a react application?

Our application will be made of 2 React.js components: Application component is a contrainer component - it encapsulates our entire React.js application. Image component on the hand - renders a single image. Let's create the Image component first: Code snippet 1.

Can you add more features to a react card component?

In the practical world, you may add all other features to it just like any other component in react. Though this tutorial is using plain ReactJS, you can use the same component structure for react-native apps as well. The card component we will be creating will look something like this -

What are the submodules of a card component in react?

This will have Header, Body and Footer as its submodules. For the tutorial purpose, I am keeping this card component very simple and not adding any complex functionality to it. In the practical world, you may add all other features to it just like any other component in react.


2 Answers

Here's a dynamic component:

Ractive.components.dynamic = Ractive.extend({
    template: '<component/>',
    components: {
        component: function() {
            return this.get('name');
        }
    },
    oninit: function(){
        this.observe('name', function(){
            this.reset();
        }, { init: false});
    }
});

Just pass in the name of the component it should implement:

<dynamic name='{{name}}'/>

See it in action below

Ractive.components.a = Ractive.extend({ template: 'I am A {{foo}}' });
Ractive.components.b = Ractive.extend({ template: 'I am B {{foo}}' });
Ractive.components.c = Ractive.extend({ template: 'I am C {{foo}}' });

Ractive.components.dynamic = Ractive.extend({
    template: '<component/>',
    components: {
        component: function() {
            return this.get('name');
        }
    },
    oninit: function(){
        this.observe('name', function(){
            this.reset();
        }, { init: false});
    }
});


var r = new Ractive({
    el: document.body,
    template: '#template',
    data: {
        foo: 'foo',
        list: ['a', 'b', 'c'],
        name: 'a'
    }
});
<script src="http://cdn.ractivejs.org/latest/ractive.js"></script>
<script id='template' type='text/ractive'>
   
    {{#each list}}
    <input type='radio' name='{{name}}' value='{{.}}'>{{.}}
    {{/each}}
    <br>
    <dynamic name='{{name}}'/>
       
</script>
like image 130
martypdx Avatar answered Oct 09 '22 10:10

martypdx


Would like to upvote @martypdx's answer more than once. Inspired by his answer, I came up with something I'd like to share. It adds the following things:

  1. Create multiple instances of a type of Component (Ractive.extend)

  2. Component instances are alive and can receive messages from external listeners even if they have been unrendered.

Here is my fiddle: https://jsfiddle.net/vikikamath/z5otgzpL/9/

// Inspired by http://stackoverflow.com/a/31080919/405117
var mapper = {
	'A': function(instanceId){
  	var handleAData;
  	return Ractive.extend({ 
  			template: 'I am A this is my data: <ul>{{#datas}}<li>{{.}}</li>{{/datas}}</ul>',
        data: {
        	datas:[]
        },
        onrender: function() {
        	handleAData = function(txt){
          	this.push('datas', txt);
          }.bind(this);
          
        	r.on(instanceId, handleAData);
        },
        onunrender: function() {
        	r.off(instanceId, handleAData);
        }
  	});
  }
  ,'B': function(instanceId){
  	var handleBData;
  	return Ractive.extend({ 
  			template: 'I am B this is my data: <ul>{{#datas}}<li>{{.}}</li>{{/datas}}</ul>',
        data: {
        	datas:[]
        },
        onrender: function() {
        	handleBData = function(txt){
          	this.push('datas', txt);
          }.bind(this);
          
        	r.on(instanceId, handleBData);
        },
        onunrender: function() {
        	r.off(instanceId, handleBData);
        }
  	});
  }
  ,'C': function(instanceId){
  	var handleCData;
  	return Ractive.extend({ 
  			template: 'I am C this is my data: <ul>{{#datas}}<li>{{.}}</li>{{/datas}}</ul>',
        data: {
        	datas:[]
        },
        onrender: function() {
        	handleCData = function(txt){
          	this.push('datas', txt);
          }.bind(this);
          
        	r.on(instanceId, handleCData);
        },
        onunrender: function() {
        	r.off(instanceId, handleCData);
        }
  	});
  }
  ,'D': function(instanceId){
  	var handleDData;
  	return Ractive.extend({ 
  			template: 'I am D this is my data: <ul>{{#datas}}<li>{{.}}</li>{{/datas}}</ul>',
        data: {
        	datas:[]
        },
        onrender: function() {
        	handleDData = function(txt){
          	this.push('datas', txt);
          }.bind(this);
          
        	r.on(instanceId, handleDData);
        },
        onunrender: function() {
        	r.off(instanceId, handleDData);
        }
  	});
  }
}

/* arbitrarily select a component */
function pickRandomComponent() {
	return String.fromCharCode(Math.floor(Math.random() * Object.keys(mapper).length) + 65);
}

var DynamicComponent = Ractive.extend({
    template: '<component/>',
    components: {
        component: function() {
            return this.get('name');
        }
    },
    oninit: function(){
        this.observe('name', function(){
            this.reset();
        }, { init: false});
    }
});


var r = new Ractive({
    el: 'main',
    template: '#template',
    components: {
    	dummy: Ractive.extend({ template: 'Welcome message' }),
    	dynamic: DynamicComponent
    },
    data: {
        foo: 'foo',
        list: ['dummy'],
        name: 'dummy',
        textdata: ''
    },
    oninit: function() {
    	this.on("sendDataToCurrentComponent", function() {
      	r.fire(this.get('name'), this.get('textdata'))
      }.bind(this));
      
    	this.on('addComponent', function(){
      	var rndComponent = pickRandomComponent();
        var now = Date.now();
        var componentInstanceName = rndComponent + '-' + now
      	this.components[componentInstanceName] = mapper[rndComponent](componentInstanceName)
      	this.push('list', componentInstanceName);
      }.bind(this));
    }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/ractive/0.7.3/ractive.min.js"></script>
<script id='template' type='text/ractive'>
   	<button on-click="addComponent">Add</button>
 		<div>
   		<input type="text" value="{{textdata}}" placeholder="Send Text to current component" width="900" on-blur="sendDataToCurrentComponent"/>
   	</div>
    {{#each list}}
    <input type='radio' name='{{name}}' value='{{.}}'>{{.}}
    {{/each}}
    <br>
    <dynamic name='{{name}}'/>
       
</script>
<main></main>
like image 45
Vikram Avatar answered Oct 09 '22 11:10

Vikram