Skip to main content

Creating React Components for POWr Settings

Create new file in app/views/apps/settings_partials​

  • Add a div with the class of your component with a powr-react attribute. This will be where the React component will render. The naming convention is powr-_<component__name>-js. Ensure you add the namespace data attr on both react component container and the hidden inout - that is what links them to each other.
  .powr-react-component-js{'powr-react': "PowrColorPicker", data: {namespace: "#{namespace}Color"}}
%input{type:'hidden', name: "#{namespace}Color", data: {label: label, namespace: "#{namespace}Color"}.merge(data)}
- Also add a hidden input to help tie React to the Backbone Model. Make sure that you add all the information you will need in your component.

- data = {namespace: namespace,label: label, options: options}.merge(params.as_json(only: [:premium_status, :help_text]))

%input{type: "hidden", name: namespace, data: data}

Pulling data out of the hidden input hash makes it a little more readable. Please don't pass the entire opts/params to data.

Add a method to app_form_helper.rb (or wherever appropriate) that will render your partial.​

  • If you are replacing an existing component with a react one, updating the existing method will mean that your component will be used everywhere that the original one was placed in settings files.
  def card_select(label, namespace, options = {})
render :partial => 'apps/settings_partials/card_select.html.haml', :locals => { label: label, namespace: namespace, options: options }
end

Create your actual component jsx file and place in app/javascript/modules/react_components​

  • REACT COMPONENT TEMPLATE
  • Name component with "Powr" in front of it, must be capitalized for react. Name file "powr_text.jsx"
  • import React from 'react'; at the top along with any other components you need.
  • If you need access to the premium status star, feature blocker, and upgrade popover, you will want to add import SettingsComponentWrapper from './settings_component_wrapper'; - that component includes all of that functionality.
  • es6 JS Class class CardSelect extends React.Component {
  • in the class, include static defaultProps, a constructor that at least calls super(props), and a render method that returns valid HTML
    • although class attributes should use className instead
    • any tags without children should be written as self-closing like <i className="fa fa-star" />
    • and all sibling elements in the return statement must be wrapped in a parent element (basically you can return a single div or something similar and can put as much as you want inside of it)
    • Example with SettingsComponentWrapper to give it premium star, feature blocking, and upgrade popover:```render () {const props = this.props;const currentClass = props.selected == props.value ? "selectedCard" : "";
return (
<li className="margin-bottom-s">
<SettingsComponentWrapper
userPremiumStatus={this.props.userPremiumStatus}
featurePremiumStatus= {this.props.plan}
anchorComponentName={this.props.value}
>
<div className="cardSelectItem" onClick={this.handleClick} >
<div className={cardSelectContainer card has-shadow container ${props.value} ${currentClass}} value={props.value} id= {props.value} >
<ImageOrIcon image_url={props.image_url} icon={props.icon} />
<div className="cardSelectText">
<h6 className="cardSelectHeadline">{props.headline}</h6>
<p className="cardSelectCaption">{props.caption}</p>
</div>
</div>
</div>
</SettingsComponentWrapper>
</li>
);

}


- export default CardSelect (your class name) at the bottom
- Please add documentation for usage, required props, and an example of calling the component at the top of the jsx file.
- For an example, see: app/javascript/modules/react_components/card_select.jsx


- ### Add your component to base_settings.jsx
- import at top of file
``` import CardSelect from "./react_components/card_select";

  • add your react component to the reactComponents hash'card-select': CardSelect ( <component-name-from-haml> : _<reactcomponentnamefromimport_> )
  • Create an initialize function that finds all instances that have not already been initialized and marks them as such and then renders your component
  • Call your initialize function in base_settings.jsx
initializeCardSelect: function() {
var self = this;
this.initializePowrReactComponents({
component: 'card-select',
propLinkedToRealInputVal: 'selected'
});
},

\AND CALL THE INITIALIZE FUNCTION IN THE CORRECT PLACE IN THE DOCUMENT
this.initializeCardSelect();

Add your CSS file to app/assets/stylesheets/partials/modules/react_components​

Import your CSS file in _settings.scss​

@import 'partials/modules/react_components/card_select.scss';


Translations​

now located at: https://www.getoutline.com/doc/translations-and-simple-copy-or-simple-copies-uvyV0IJq16

Triggers​

These happen automatically using initializePowrReactComponents but if you want to handle special cases here is how you can use two triggers:

Tp update the backbone model to match the value of the react component, call

$realInput.trigger('reactUpdateRequest');

Then you can listen to

el.on('change reactUpdateRequest', '[name="type"]', function() {

To update the react component's state, update the data attribute and call

$realInput
.data('placeholder', 'cheese')
.trigger('forceUpdateComponent');