<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Software Development Archives | DMC, Inc.</title>
	<atom:link href="https://static.dmcinfo.com/blog/tag/software-development/feed/index.xml" rel="self" type="application/rss+xml" />
	<link></link>
	<description></description>
	<lastBuildDate>Fri, 24 Jul 2026 18:37:48 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.2</generator>

<image>
	<url>https://static.dmcinfo.com/wp-content/uploads/2025/04/site-icon-150x150.png</url>
	<title>Software Development Archives | DMC, Inc.</title>
	<link></link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>5 Great Ways to Get Started with React Components</title>
		<link>https://static.dmcinfo.com/blog/22512/5-great-ways-to-get-started-with-react-components/</link>
		
		<dc:creator><![CDATA[DMC]]></dc:creator>
		<pubDate>Wed, 07 Nov 2018 15:55:14 +0000</pubDate>
				<category><![CDATA[Application Development]]></category>
		<category><![CDATA[Web Application Development]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Web]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/22512/5-great-ways-to-get-started-with-react-components/</guid>

					<description><![CDATA[<p>React has quickly become one of DMC’s favorite tools for web frontend development due to its component-based structure and growing adoption. However, between the JSX syntax, component lifecycle, and state management, learning to use React effectively sometimes feels like learning a language in and of itself.&#160; If you&#8217;re getting your feet wet in React, here [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/22512/5-great-ways-to-get-started-with-react-components/">5 Great Ways to Get Started with React Components</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">React has quickly become one of DMC’s favorite tools for <a href="/services/application-development/web-application-development">web frontend development</a> due to its component-based structure and growing adoption.</p>



<p class="wp-block-paragraph">However, between the JSX syntax, component lifecycle, and state management, learning to use React effectively sometimes feels like learning a language in and of itself.&nbsp;</p>



<p class="wp-block-paragraph">If you&#8217;re getting your feet wet in React, here are some of DMC’s top tips for making components.</p>



<h2 class="wp-block-heading" id="h-1-make-lots-of-components"><strong>1. Make Lots of Components</strong></h2>



<p class="wp-block-paragraph">React’s component-based structure allows very convenient segmentation of different portions of a user interface. However, it can often be unclear where one component should end and&nbsp;where another component should begin. If you were to recreate this page in React, would the Categories listing be a component or just a portion of a component for the whole page? Would each section be a&nbsp;component? Would each link?</p>



<p class="wp-block-paragraph">Often, large components that have a lot of different functionality mixed is a sign of a newer React developer. Just as with object-oriented code, breaking down classes or functions to their essentials and handing off the specifics to helpers makes the code a lot more readable and easier to maintain.&nbsp;</p>



<p class="wp-block-paragraph">In our experience, if you’re asking the question, “Should this be a separate component?” the answer is probably yes.</p>



<p class="wp-block-paragraph">Regarding hard and fast rules, the following guidelines have served us well. <strong>You should pull UI code into a unique component if:</strong></p>



<ul class="wp-block-list">
<li>You want to use the same (or a parameterized version of the same) element elsewhere in your application</li>



<li>You want each item in a list of data to have a similar display (in other words, you want to map a list of data to it)</li>



<li>It forms its own functionally or visually distinct section or subsection</li>
</ul>



<p class="wp-block-paragraph">For example, you&nbsp;<em>could</em>&nbsp;implement the Categories sidebar on this site doing something similar to the following. This approach is hard to read, debug, and maintain &#8211; splitting each UI section in a map into its separate components would be better.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">JavaScript</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>render() {
    return (
        &lt;div>
            &lt;h1>Categories&lt;/h1>
            {this.props.categories.map(category => (
                &lt;div>
                    &lt;h2>{category.name}&lt;/h2>
                    &lt;ul>
                        {category.subCategories.map(subCategory => (
                            &lt;div>
                                &lt;li className="bullet">{subCategory.name}&lt;/li>
                                {subCategory.subSubCategories.map(subSubCategory => (
                                    &lt;div>
                                        &lt;li className="indented-bullet">{subSubCategory}&lt;/li>
                                    &lt;/div>
                                ))}
                            &lt;/div>
                        ))}
                    &lt;/ul>
                &lt;/div>
            ))}
        &lt;/div>
    );
}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #DCDCAA">render</span><span style="color: #D4D4D4">() {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> (</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #808080">&lt;</span><span style="color: #569CD6">div</span><span style="color: #808080">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #808080">&lt;</span><span style="color: #569CD6">h1</span><span style="color: #808080">&gt;</span><span style="color: #D4D4D4">Categories</span><span style="color: #808080">&lt;/</span><span style="color: #569CD6">h1</span><span style="color: #808080">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #569CD6">{this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">props</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">categories</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">map</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">category</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> (</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #808080">&lt;</span><span style="color: #569CD6">div</span><span style="color: #808080">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">                    </span><span style="color: #808080">&lt;</span><span style="color: #569CD6">h2</span><span style="color: #808080">&gt;</span><span style="color: #569CD6">{</span><span style="color: #9CDCFE">category</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">name</span><span style="color: #569CD6">}</span><span style="color: #808080">&lt;/</span><span style="color: #569CD6">h2</span><span style="color: #808080">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">                    </span><span style="color: #808080">&lt;</span><span style="color: #569CD6">ul</span><span style="color: #808080">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">                        </span><span style="color: #569CD6">{</span><span style="color: #9CDCFE">category</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">subCategories</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">map</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">subCategory</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> (</span></span>
<span class="line"><span style="color: #D4D4D4">                            </span><span style="color: #808080">&lt;</span><span style="color: #569CD6">div</span><span style="color: #808080">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">                                </span><span style="color: #808080">&lt;</span><span style="color: #569CD6">li</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">className</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;bullet&quot;</span><span style="color: #808080">&gt;</span><span style="color: #569CD6">{</span><span style="color: #9CDCFE">subCategory</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">name</span><span style="color: #569CD6">}</span><span style="color: #808080">&lt;/</span><span style="color: #569CD6">li</span><span style="color: #808080">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">                                </span><span style="color: #569CD6">{</span><span style="color: #9CDCFE">subCategory</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">subSubCategories</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">map</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">subSubCategory</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> (</span></span>
<span class="line"><span style="color: #D4D4D4">                                    </span><span style="color: #808080">&lt;</span><span style="color: #569CD6">div</span><span style="color: #808080">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">                                        </span><span style="color: #808080">&lt;</span><span style="color: #569CD6">li</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">className</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;indented-bullet&quot;</span><span style="color: #808080">&gt;</span><span style="color: #569CD6">{</span><span style="color: #9CDCFE">subSubCategory</span><span style="color: #569CD6">}</span><span style="color: #808080">&lt;/</span><span style="color: #569CD6">li</span><span style="color: #808080">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">                                    </span><span style="color: #808080">&lt;/</span><span style="color: #569CD6">div</span><span style="color: #808080">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">                                ))</span><span style="color: #569CD6">}</span></span>
<span class="line"><span style="color: #D4D4D4">                            </span><span style="color: #808080">&lt;/</span><span style="color: #569CD6">div</span><span style="color: #808080">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">                        ))</span><span style="color: #569CD6">}</span></span>
<span class="line"><span style="color: #D4D4D4">                    </span><span style="color: #808080">&lt;/</span><span style="color: #569CD6">ul</span><span style="color: #808080">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #808080">&lt;/</span><span style="color: #569CD6">div</span><span style="color: #808080">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">            ))</span><span style="color: #569CD6">}</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #808080">&lt;/</span><span style="color: #569CD6">div</span><span style="color: #808080">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">    );</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<h2 class="wp-block-heading" id="h-nbsp">&nbsp;</h2>



<h2 class="wp-block-heading" id="h-2-make-lots-of-functional-nbsp-components"><strong>2. Make Lots of <em>Functional</em>&nbsp;Components</strong></h2>



<p class="wp-block-paragraph">As you make more components, you’ll need to <a href="https://reactjs.org/docs/lifting-state-up.html">lift state up</a>&nbsp;by lifting shared state up to the closest common ancestor. Sometimes, you’ll only need to pull one value out of a component’s state and leave it otherwise unchanged. But often, a component that doesn’t have any state&nbsp;remains. If this is the case, it is an excellent opportunity to convert to functional components.</p>



<p class="wp-block-paragraph">We find that <strong>functional components</strong> (<a href="https://reactjs.org/docs/components-and-props.html">components</a> which are used as a function call rather than as a class instance) are often more concise and better broken up than components that rely heavily on state. Functional components are also simple to debug. It&#8217;s clear what to&nbsp;render on the page b<span style="background-color: rgb(245, 246, 245);">ased on what&#8217;s passed into the component.</span><span style="background-color: rgb(245, 246, 245);">&nbsp;</span>&nbsp;</p>



<p class="wp-block-paragraph">As you begin to convert your components over to functional versions, you may notice you have separate components for data management and display. Dividing components into two categories is a whole different way of thinking,&nbsp;best explained by <a href="https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0">Dan Abramov</a>.</p>



<p class="wp-block-paragraph">&nbsp;</p>



<h2 class="wp-block-heading" id="h-3-consider-nbsp-a-state-management-library"><strong>3. Consider&nbsp;a State Management Library</strong></h2>



<p class="wp-block-paragraph">As your state begins to lift higher and higher in your application, you will flow&nbsp;through <strong>Container components</strong> to drive <strong>Presentational components.</strong>&nbsp;You may start to notice that a portion of the component state drives the display of another component&nbsp;nested deeply within its children components.</p>



<p class="wp-block-paragraph">If the state of your application is already far from the display it drives, then it&#8217;s likely time to consider a <strong>state management library</strong>.</p>



<p class="wp-block-paragraph"><strong>State management libraries</strong> allow you to interact with the (likely centrally-held) state of your application consistently and predictably. It minimizes the need to pass so many props as well as to update functions between components. <strong>Redux </strong>is probably the most popular option for managing state in <strong>React </strong>applications, but there are many options out there (including MobX and Unstated).</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Redux-edited.jpg" alt="react and redux"/></figure>



<p class="wp-block-paragraph">&nbsp;</p>



<p class="wp-block-paragraph">Integrating a state management library can simplify complex interactions between states for different components, but tends to produce more <strong>‘boiler-plate’</strong> code.</p>



<p class="wp-block-paragraph">&nbsp;</p>



<h2 class="wp-block-heading" id="h-4-make-some-async-components"><strong>4. Make Some Async Components</strong></h2>



<p class="wp-block-paragraph">On the other hand, if your app is comparatively small or you don’t want the overhead of a component management library, you may end up using the component lifecycle methods to give a component asynchronous functionality. The component can then interact with some external data source on its own.</p>



<p class="wp-block-paragraph">Let’s say that we’re building a sidebar for a grid of houses. Whenever a user clicks on the row for the house, the sidebar fetches the data for that house from some external source and displays it. Here’s what a <strong>container component</strong> for that might look like:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">TypeScript</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>interface State {
    house?: House;
}

interface Props {
    houseId: number;
}

class HouseSidebarContainer extends React.Component&lt;Props, State> {
    constructor (props: Props) {
        super(props);
        this.state = {
        };

        this.loadHouse = this.loadHouse.bind(this);
    }

    async componentDidMount(){
        await this.loadHouse(this.props.houseId);
    }

    async componentDidUpdate(prevProps: Props){
        if (prevProps.houseId !== this.props.houseId) {
            await this.loadHouse(this.props.houseId);
        }
    }

    render () {
        return this.state.house 
            ? &lt;HouseDisplay {...house} />
            : &lt;LoadingSpinner />;
    }

    async loadHouse(houseId: number) {
        let houseData = await fetchHouse(houseId);
        if (houseData) {
            this.setState({house: houseData})
        }
    }
}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">interface</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">State</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">house</span><span style="color: #D4D4D4">?: </span><span style="color: #4EC9B0">House</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">interface</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Props</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">houseId</span><span style="color: #D4D4D4">: </span><span style="color: #4EC9B0">number</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">class</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">HouseSidebarContainer</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">extends</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">React</span><span style="color: #D4D4D4">.</span><span style="color: #4EC9B0">Component</span><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">Props</span><span style="color: #D4D4D4">, </span><span style="color: #4EC9B0">State</span><span style="color: #D4D4D4">&gt; {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">constructor</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">props</span><span style="color: #D4D4D4">: </span><span style="color: #4EC9B0">Props</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">super</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">props</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">state</span><span style="color: #D4D4D4"> = {</span></span>
<span class="line"><span style="color: #D4D4D4">        };</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">loadHouse</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">loadHouse</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">bind</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">componentDidMount</span><span style="color: #D4D4D4">(){</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">loadHouse</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">props</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">houseId</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">componentDidUpdate</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">prevProps</span><span style="color: #D4D4D4">: </span><span style="color: #4EC9B0">Props</span><span style="color: #D4D4D4">){</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">prevProps</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">houseId</span><span style="color: #D4D4D4"> !== </span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">props</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">houseId</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">loadHouse</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">props</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">houseId</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">render</span><span style="color: #D4D4D4"> () {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">state</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">house</span><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #D4D4D4">            ? &lt;</span><span style="color: #4EC9B0">HouseDisplay</span><span style="color: #D4D4D4"> {...</span><span style="color: #4EC9B0">house</span><span style="color: #D4D4D4">} /&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">            : &lt;</span><span style="color: #4EC9B0">LoadingSpinner</span><span style="color: #D4D4D4"> /&gt;;</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">loadHouse</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">houseId</span><span style="color: #D4D4D4">: </span><span style="color: #4EC9B0">number</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">let</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">houseData</span><span style="color: #D4D4D4"> = </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">fetchHouse</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">houseId</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">houseData</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">setState</span><span style="color: #D4D4D4">({</span><span style="color: #9CDCFE">house:</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">houseData</span><span style="color: #D4D4D4">})</span></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph">The significant thing to recognize is that the <strong>render function</strong> cannot be asynchronous, so any asynchronous logic must be handled outside of the render function and updated in state.</p>



<p class="wp-block-paragraph">The other thing to remember is that changing the props (in this case, the viewed house) doesn’t trigger a remount of the component, and must be watched manually by the <strong>componentDidUpdate</strong> function.</p>



<p class="wp-block-paragraph">&nbsp;</p>



<h2 class="wp-block-heading" id="h-5-use-other-people-s-components"><strong>5. Use Other People&#8217;s Components</strong></h2>



<p class="wp-block-paragraph">Now that you’re getting pretty good at making your own React components, it’s time to avoid it as much as possible! I’m joking, but it’s important not to spend <strong>too much</strong> of your time on components that are common to a lot of applications.</p>



<p class="wp-block-paragraph">Simple items, like <strong>breadcrumbs</strong>, don’t take too long to implement, but that time can pile up when you implement each one yourself. More complex items, like a <strong>datepicker</strong>, may take substantial development effort to implement. The good news is that someone has done this before, and you can take advantage of their experience. The bad news is that it can be challenging to identify the best implementation out there, and using a component that’s buggy or has a poor API can cost you as much time as implementing it yourself.</p>



<p class="wp-block-paragraph">This&nbsp;time loss is especially true for simple components: it may take just as long to fit in a simple third-party component with options that don’t quite fit as it does to write the component yourself. In such instances, larger sets of components with similar interfaces (<strong>a component library</strong>) can speed up development.</p>



<p class="wp-block-paragraph">When you start working on a new app, it’s worth your time to investigate using a component library, which will allow you to use a wide set of components with similar interfaces and uniform styles. There’s a <a href="https://blog.bitsrc.io/11-react-component-libraries-you-should-know-178eb1dd6aa4">wide variety</a> out there, each with its pros and cons.&nbsp;</p>



<p class="wp-block-paragraph">Based on our experience, we recommend picking a library that already looks similar to the app you want to build. While most libraries offer some way to customize their styling, if you have to make a lot of styling changes to each component, you haven’t saved much time over implementing your own components. Component libraries we’ve enjoyed recently include React Material-UI, Semantic UI, and Reactstrap.</p>



<p class="wp-block-paragraph">Even if you pick the best possible library for your project, it’s&nbsp;unlikely to contain every single UI component you need. You’re likely to need to pick up at least one or two components a la carte, like a chart, datepicker, or a treeview. </p>



<p class="wp-block-paragraph">Just like when using any external dependency, you’ll want to make sure that whatever you pick is being actively used and maintained, that the API makes sense to you, and that the license fits the needs of your application.</p>



<p class="wp-block-paragraph"><strong><a href="/services/application-development">Learn more about DMC&#8217;s Application Development Services</a></strong></p>
<p>The post <a href="https://static.dmcinfo.com/blog/22512/5-great-ways-to-get-started-with-react-components/">5 Great Ways to Get Started with React Components</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>DMC Attends Inaugural TwinCAT HMI Training</title>
		<link>https://static.dmcinfo.com/blog/22685/dmc-attends-inaugural-twincat-hmi-training/</link>
		
		<dc:creator><![CDATA[DMC]]></dc:creator>
		<pubDate>Mon, 17 Sep 2018 10:33:52 +0000</pubDate>
				<category><![CDATA[HMI and SCADA]]></category>
		<category><![CDATA[Manufacturing Automation & Intelligence]]></category>
		<category><![CDATA[PLC]]></category>
		<category><![CDATA[User Interface Design]]></category>
		<category><![CDATA[Web Application Development]]></category>
		<category><![CDATA[Beckhoff and TwinCAT]]></category>
		<category><![CDATA[HTML and CSS]]></category>
		<category><![CDATA[MS Visual Studio/.NET]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Web]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/22685/dmc-attends-inaugural-twincat-hmi-training/</guid>

					<description><![CDATA[<p>Earlier this year, DMC attended a training course on the new TwinCAT HMI at Beckhoff&#8217;s U.S. headquarters in Savage, MN. We were impressed by the flexibility and convenience offered by the platform and have already enjoyed using it on projects. Due to its unique developer-friendly design, DMC has been able to reduce development time and [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/22685/dmc-attends-inaugural-twincat-hmi-training/">DMC Attends Inaugural TwinCAT HMI Training</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p class="wp-block-paragraph">Earlier this year, DMC attended a training course on the new TwinCAT HMI at Beckhoff&rsquo;s U.S. headquarters in Savage, MN. We were impressed by the flexibility and convenience offered by the platform and have already enjoyed using it on projects. Due to its unique developer-friendly design, DMC has been able to reduce development time and save money for our clients. Here&rsquo;s a couple of the features of Beckhoff&rsquo;s new HMI that set it apart:</p>

<p class="wp-block-paragraph"><strong>Web-based Control and Monitoring</strong></p>

<p class="wp-block-paragraph">The most appealing aspect of Beckhoff&rsquo;s platform is that it leverages the internet to allow end users to control and monitor their PLCs from anywhere. Interfacing with industrial controllers via the internet is a common request for DMC, and the TwinCAT HMI makes this easier than ever before with integrated server- and client-side development connecting easily to the underlying PLC access. The key benefit is that a web-based HMI can be accessed from any number of different clients &ndash; a traditional monitor screen nearby the device being controlled, a tablet carried around the area by a supervisor, or even a mobile phone halfway around the world. The HMI includes a responsive grid designed to facilitate development for multiple device sizes.</p>

<figure class="wp-block-image"><img decoding="async" alt="Multiple Web Clients for TwinCAT HMI Server" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/TCHMI-Multi-Client_1.jpg"  /></figure>

<p class="wp-block-paragraph"><strong>WYSIWYG Web Page Design</strong></p>

<p class="wp-block-paragraph">As any web developer can tell you, managing the location and arrangement of content on the page can be one of the most time-consuming aspects to do manually. Development for TwinCAT gets around these issues using a What You See Is What You Get style editor, paired with other features to make life easy for developers. Selecting and arranging components is as simple as dragging them in from a menu. The HMI features dozens of prebuilt components, including commonly used displays and controls, as well as advanced charts. We walked through a demo project using several different charts, which update live when linked with the PLC data, making it very easy to display live system data of all sorts to your end users.</p>

<figure class="wp-block-image"><img decoding="async" alt="TwinCAT HMI Development in Visual Studio" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/TCHMI-VS.jpg"  /></figure>

<p class="wp-block-paragraph"><strong>Development in Visual Studio</strong></p>

<p class="wp-block-paragraph">This is a good point to bring up the ease of development afforded by the IDE. Development for the HMI is integrated directly into Visual Studio, which is very familiar to DMC from our extensive .NET development. The Visual Studio pane and menu system&rsquo;s familiarity makes navigation quick, and Beckhoff&rsquo;s custom screens are also very easy to use. Integrating development into a widely used and well-regarded editor allows engineers to develop a simple web-based HMIs for their PLCs without requiring extensive knowledge of web technologies. However, developers familiar with web technologies (like DMC) still have access to the generated results, allowing us to tailor a solution to the exact needs of our clients.</p>

<p class="wp-block-paragraph"><strong>Easy Extension and Customization</strong></p>

<p class="wp-block-paragraph">As mentioned, Beckhoff&rsquo;s existing framework controls allow for rapid development, especially for simple applications. However, the HMI is also very extensible, allowing for flexible and very custom solutions. DMC took an additional course in designing extensions for custom applications. The extensibility allows for custom Javascript interactive controls, in the case that the provided components don&rsquo;t quite fit the bill. Further, the HMI allows for custom server controls in C#, which allows us to develop connect to any system, use any library, or employ any custom code from our .NET expertise. The flexibility of these extensions, combined with the ease of creating a simple solution, makes us very excited to work on projects with this new HMI.</p>

<p class="wp-block-paragraph">Thanks to Zachary Daulton and co. at Beckhoff for hosting us and giving us a preview of the software!</p>
<p>The post <a href="https://static.dmcinfo.com/blog/22685/dmc-attends-inaugural-twincat-hmi-training/">DMC Attends Inaugural TwinCAT HMI Training</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>5 Great Uses of the Spread Operator in a React App</title>
		<link>https://static.dmcinfo.com/blog/22847/5-great-uses-of-the-spread-operator-in-a-react-app/</link>
		
		<dc:creator><![CDATA[DMC]]></dc:creator>
		<pubDate>Thu, 02 Aug 2018 10:21:15 +0000</pubDate>
				<category><![CDATA[Application Development]]></category>
		<category><![CDATA[Web Application Development]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Web]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/22847/5-great-uses-of-the-spread-operator-in-a-react-app/</guid>

					<description><![CDATA[<p>React has quickly become one of DMC’s favorite tools for web front-end development due to its component-based structure and growing adoption. However, between the JSX syntax, component lifecycle, and state management, learning to use React effectively sometimes feels like learning a language in and of itself. JavaScript’s spread operator sees a lot of use in [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/22847/5-great-uses-of-the-spread-operator-in-a-react-app/">5 Great Uses of the Spread Operator in a React App</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">React has quickly become one of DMC’s favorite tools for web front-end development due to its component-based structure and growing adoption. However, between the JSX syntax, component lifecycle, and state management, learning to use React effectively sometimes feels like learning a language in and of itself.<br>
<br>
JavaScript’s <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax">spread operator</a> sees a lot of use in DMC’s React applications due to its concision and versatility. Here are 5 of our favorite uses of the spread operator (…) in a React application.<br>
&nbsp;</p>



<h2 class="wp-block-heading" id="h-1-passing-props-nbsp"><strong>1. Passing props</strong><br>
&nbsp;</h2>



<p class="wp-block-paragraph">Probably the most common usage of the spread operator in a React app is in passing props down to a child component. So long as the object you’re spreading includes all the properties the child component requires, the child component will use those and ignore the extraneous ones.<br>
<br>
This allows for much more concise code than breaking out each property that the child inherits from the parent. Note: we use Typescript in our applications, and these examples will use it as well for clarity.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">TypeScript</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>interface LabeledButtonProps extends ButtonProps {
    labelText: string;
}

const LabeledButton = (props: LabeledButtonProps) => (
    &lt;div>
        {props.labelText}
        &lt;Button {...props} />
    &lt;/div>
);</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">interface</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">LabeledButtonProps</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">extends</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">ButtonProps</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">labelText</span><span style="color: #D4D4D4">: </span><span style="color: #4EC9B0">string</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">LabeledButton</span><span style="color: #D4D4D4"> = (</span><span style="color: #9CDCFE">props</span><span style="color: #D4D4D4">: </span><span style="color: #4EC9B0">LabeledButtonProps</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> (</span></span>
<span class="line"><span style="color: #D4D4D4">    &lt;</span><span style="color: #4EC9B0">div</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        {</span><span style="color: #9CDCFE">props</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">labelText</span><span style="color: #D4D4D4">}</span></span>
<span class="line"><span style="color: #D4D4D4">        &lt;</span><span style="color: #9CDCFE">Button</span><span style="color: #D4D4D4"> {...</span><span style="color: #9CDCFE">props</span><span style="color: #D4D4D4">} /&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">    &lt;/</span><span style="color: #9CDCFE">div</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">);</span></span></code></pre></div>



<h2 class="wp-block-heading" id="h-2-generating-multiple-component-instances-with-common-props-nbsp"><br>
<strong>2. Generating multiple component instances with common props</strong><br>
&nbsp;</h2>



<p class="wp-block-paragraph">If you have multiple component instances with some attributes in common, and others which differ, it can be helpful to pull them out into one object which is referenced by all instances. For example, instead of the following:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">TypeScript</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>render () {
    return (
        &lt;div>
            &lt;Button height={20} width={40} color="red" text="Press Here"/>
            &lt;Button height={20} width={40} color="red" text="Or Here!"/>
            &lt;Button height={20} width={40} color="red" text="(Even Here)"/>
        &lt;/div>
    );
}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #DCDCAA">render</span><span style="color: #D4D4D4"> () {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> (</span></span>
<span class="line"><span style="color: #D4D4D4">        &lt;</span><span style="color: #4EC9B0">div</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">            &lt;</span><span style="color: #9CDCFE">Button</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">height</span><span style="color: #D4D4D4">={</span><span style="color: #B5CEA8">20</span><span style="color: #D4D4D4">} </span><span style="color: #9CDCFE">width</span><span style="color: #D4D4D4">={</span><span style="color: #B5CEA8">40</span><span style="color: #D4D4D4">} </span><span style="color: #9CDCFE">color</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;red&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">text</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;Press Here&quot;</span><span style="color: #D4D4D4">/&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">            &lt;</span><span style="color: #9CDCFE">Button</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">height</span><span style="color: #D4D4D4">={</span><span style="color: #B5CEA8">20</span><span style="color: #D4D4D4">} </span><span style="color: #9CDCFE">width</span><span style="color: #D4D4D4">={</span><span style="color: #B5CEA8">40</span><span style="color: #D4D4D4">} </span><span style="color: #9CDCFE">color</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;red&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">text</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;Or Here!&quot;</span><span style="color: #D4D4D4">/&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">            &lt;</span><span style="color: #9CDCFE">Button</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">height</span><span style="color: #D4D4D4">={</span><span style="color: #B5CEA8">20</span><span style="color: #D4D4D4">} </span><span style="color: #9CDCFE">width</span><span style="color: #D4D4D4">={</span><span style="color: #B5CEA8">40</span><span style="color: #D4D4D4">} </span><span style="color: #9CDCFE">color</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;red&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">text</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;(Even Here)&quot;</span><span style="color: #D4D4D4">/&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        &lt;/</span><span style="color: #9CDCFE">div</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">    );</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph">You can instead abstract the common props:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">TypeScript</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>render () {
    let commonButtonAttributes: PartialButtonProps = {
        height: 20, width: 40, color: 'red'
    }
    return (
        &lt;div>
            &lt;Button {...commonButtonAttributes} text="Press Here"/>
            &lt;Button {...commonButtonAttributes} text="Or Here!"/>
            &lt;Button {...commonButtonAttributes} text="(Even Here)"/>
        &lt;/div>
    );
}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #DCDCAA">render</span><span style="color: #D4D4D4"> () {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">let</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">commonButtonAttributes</span><span style="color: #D4D4D4">: </span><span style="color: #4EC9B0">PartialButtonProps</span><span style="color: #D4D4D4"> = {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">height:</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">20</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">width:</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">40</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">color:</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&apos;red&apos;</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> (</span></span>
<span class="line"><span style="color: #D4D4D4">        &lt;</span><span style="color: #4EC9B0">div</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">            &lt;</span><span style="color: #9CDCFE">Button</span><span style="color: #D4D4D4"> {...</span><span style="color: #9CDCFE">commonButtonAttributes</span><span style="color: #D4D4D4">} </span><span style="color: #9CDCFE">text</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;Press Here&quot;</span><span style="color: #D4D4D4">/&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">            &lt;</span><span style="color: #9CDCFE">Button</span><span style="color: #D4D4D4"> {...</span><span style="color: #9CDCFE">commonButtonAttributes</span><span style="color: #D4D4D4">} </span><span style="color: #9CDCFE">text</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;Or Here!&quot;</span><span style="color: #D4D4D4">/&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">            &lt;</span><span style="color: #9CDCFE">Button</span><span style="color: #D4D4D4"> {...</span><span style="color: #9CDCFE">commonButtonAttributes</span><span style="color: #D4D4D4">} </span><span style="color: #9CDCFE">text</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;(Even Here)&quot;</span><span style="color: #D4D4D4">/&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        &lt;/</span><span style="color: #9CDCFE">div</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">    );</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph">Similarly, you can map a function which generates an instance of the component using these common props over an array of the unique elements (shown in example 4), which is preferable for longer or dynamic element lists.<br>
&nbsp;</p>



<h2 class="wp-block-heading" id="h-3-setting-the-state-with-dynamic-key-name-nbsp"><strong>3. Setting the state with dynamic key name</strong><br>
&nbsp;</h2>



<p class="wp-block-paragraph">Leaving our button for a moment, another place where we frequently use the spread operator is in functions to handle change events for forms. We typically use the same function to handle changes for all fields in a form, to minimize code repetition.<br>
<br>
The following syntax allows setting a property in the state with a dynamic key name&nbsp;while maintaining the other properties previously in the state:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">TypeScript</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>handleChange(name: string, value: string | number) {
    this.setState({ ...this.state, &#91;name&#93;: value });
}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #DCDCAA">handleChange</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">name</span><span style="color: #D4D4D4">: </span><span style="color: #9CDCFE">string</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">value</span><span style="color: #D4D4D4">: </span><span style="color: #9CDCFE">string</span><span style="color: #D4D4D4"> | </span><span style="color: #9CDCFE">number</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">setState</span><span style="color: #D4D4D4">({ ...</span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">state</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">&#91;name&#93;:</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">value</span><span style="color: #D4D4D4"> });</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph">As a note, this pattern is not necessary if using React without using Typescript. This is also a good point to emphasize the importance of order when using the spread operator. I like to think of the spread operator as literally spreading out (in order) the items in an object or list.<br>
<br>
If you’re trying to overwrite an existing property, as I am in this case, it’s important to make sure it’s after the spread operator, or the existing property will overwrite your new value!<br>
&nbsp;</p>



<h2 class="wp-block-heading" id="h-4-adding-a-single-item-to-the-start-or-the-end-of-an-array-nbsp"><strong>4. Adding a single item to the start or the end of an array</strong><br>
&nbsp;</h2>



<p class="wp-block-paragraph">The spread operator can also be used working with arrays, which can be very useful in a React application. One situation we encounter frequently is adding an element to an array which is subsequently mapped and rendered. Doing so with the spread operator is simpler and cleaner than doing so with Javascript’s push() or concat().<br>
<br>
For example, if our button list always needs to include a cancel button, we could do the following:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">TypeScript</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>const ButtonList = (buttonTexts: string[]) =>
    &#91;...buttonTexts, 'Cancel'&#93;.map((buttonText, index) =>
        &lt;Button
            key={index}
            text={buttonText}
            {...commonButtonAttributes}
        />
    );</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">ButtonList</span><span style="color: #D4D4D4"> = (</span><span style="color: #9CDCFE">buttonTexts</span><span style="color: #D4D4D4">: </span><span style="color: #4EC9B0">string</span><span style="color: #D4D4D4">[]) </span><span style="color: #569CD6">=&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">    &#91;...</span><span style="color: #9CDCFE">buttonTexts</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&apos;Cancel&apos;</span><span style="color: #D4D4D4">&#93;.</span><span style="color: #DCDCAA">map</span><span style="color: #D4D4D4">((</span><span style="color: #9CDCFE">buttonText</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">index</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">=&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        &lt;</span><span style="color: #9CDCFE">Button</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">key</span><span style="color: #D4D4D4">={</span><span style="color: #9CDCFE">index</span><span style="color: #D4D4D4">}</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">text</span><span style="color: #D4D4D4">={</span><span style="color: #9CDCFE">buttonText</span><span style="color: #D4D4D4">}</span></span>
<span class="line"><span style="color: #D4D4D4">            {...</span><span style="color: #9CDCFE">commonButtonAttributes</span><span style="color: #D4D4D4">}</span></span>
<span class="line"><span style="color: #D4D4D4">        /&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">    );</span></span></code></pre></div>



<h2 class="wp-block-heading" id="h-5-stripping-properties-using-destructuring-nbsp"><br>
<strong>5. Stripping properties using destructuring</strong><br>
&nbsp;</h2>



<p class="wp-block-paragraph">Our final favorite use of the spread operator is to strip properties from an existing object to make a new object without setting properties individually. We’ve found this most useful when making calls to an API, when we want to be careful to send only the data we intend.<br>
<br>
Specifying all the properties we want on the new object can be quite verbose:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">TypeScript</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>let locationUpdate = {
    name: this.state.name,
    address: this.state.address,
    locationId: this.state.locationId,
    etc…
}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">let</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">locationUpdate</span><span style="color: #D4D4D4"> = {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">name:</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">state</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">name</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">address:</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">state</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">address</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">locationId:</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">state</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">locationId</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">    etc…</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph">Instead, by using destructuring with the rest syntax, we can specify the properties we want to exclude from the new object.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">TypeScript</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>let { isLoading, availableLocations, ...locationUpdate } = this.state;</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">let</span><span style="color: #D4D4D4"> { </span><span style="color: #9CDCFE">isLoading</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">availableLocations</span><span style="color: #D4D4D4">, ...</span><span style="color: #9CDCFE">locationUpdate</span><span style="color: #D4D4D4"> } = </span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">state</span><span style="color: #D4D4D4">;</span></span></code></pre></div>



<h2 class="wp-block-heading" id="h-conclusion"><br>
<strong>Conclusion</strong></h2>



<p class="wp-block-paragraph"><br>
Javascript’s spread operator is a powerful tool to minimize boilerplate in a React application and make it easy to read and maintain in addition to its natural performance benefits.<br>
<br>
If you’re interested in working with DMC on a React application, feel free to <a href="https://static.dmcinfo.com/contact">contact us</a>.</p>
<p>The post <a href="https://static.dmcinfo.com/blog/22847/5-great-uses-of-the-spread-operator-in-a-react-app/">5 Great Uses of the Spread Operator in a React App</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Frame Accurate Video Scrubbing in the Client</title>
		<link>https://static.dmcinfo.com/blog/23297/frame-accurate-video-scrubbing-in-the-client/</link>
		
		<dc:creator><![CDATA[DMC]]></dc:creator>
		<pubDate>Wed, 28 Mar 2018 11:50:32 +0000</pubDate>
				<category><![CDATA[Application Development]]></category>
		<category><![CDATA[Web Application Development]]></category>
		<category><![CDATA[HTML and CSS]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Web]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/23297/frame-accurate-video-scrubbing-in-the-client/</guid>

					<description><![CDATA[<p>There are a variety of desktop applications that allow users to seamlessly scrub back and forth through a video to determine the exact frame in which some action should take place or where the placement of a tag should go. Some popular applications include Final Cut Pro and Adobe Premiere Pro. This sort of smooth [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/23297/frame-accurate-video-scrubbing-in-the-client/">Frame Accurate Video Scrubbing in the Client</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">There are a variety of desktop applications that allow users to seamlessly scrub back and forth through a video to determine the exact frame in which some action should take place or where the placement of a tag should go. Some popular applications include Final Cut Pro and Adobe Premiere Pro. This sort of smooth functionality is difficult to attain on a website due to the limited resources of a browser client in comparison with a desktop environment.&nbsp;</p>



<p class="wp-block-paragraph">In this post, I will walk through how to create a simple frame-accurate video scrubber for video segments in a browser client using the HTML5 video element.</p>



<p class="wp-block-paragraph">The inspiration for this scrubber implementation comes from this Github post: <a href="https://jordicenzano.github.io/frame-accurate-scrubbing/">Frame Accurate Scrubbing</a>, which describes a method that would extract frames on the backend and serve them up to a client for accurate scrubbing.</p>



<p class="wp-block-paragraph">There are many great open-source packages that make for a simple frame grabbing implementation on the backend, and most of these packages rely on FFMPEG to decode video.&nbsp;</p>



<p class="wp-block-paragraph">Since GPL distributes&nbsp;<span style="background-color: rgb(245, 246, 245);">FFmpeg</span>, this is an approach that can be incompatible with projects that aren’t destined to be open source or also distributed under GPL. By using the HTML5 video element to extract frames, we can avoid FFPMEG’s viral GPL license as well as the hassle of writing the video decoder ourselves.</p>



<h2 class="wp-block-heading" id="h-environment">Environment</h2>



<p class="wp-block-paragraph">The examples below show the JSX markup of the development we did in React JS.</p>



<h2 class="wp-block-heading" id="h-prerequisites">Prerequisites</h2>



<p class="wp-block-paragraph">This implementation requires a known framerate for the video you want to use. Additionally, I did this development using a Chrome browser, which supports the MP4 video format that I was using. Make sure that your <a href="https://en.wikipedia.org/wiki/HTML5_video#Browser_support">browser&nbsp;supports your desired video format</a>&nbsp;for HTML5 video.</p>



<p class="wp-block-paragraph">With that out of the way, let’s get started!</p>



<h2 class="wp-block-heading" id="h-html5-video-element-as-video-decoder">HTML5 Video Element as Video Decoder</h2>



<p class="wp-block-paragraph"><strong>Create an HTML5 Video component</strong> on your page, but keep it hidden. Store a reference to this video player. Also, create a div to hold the extracted frames.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">JavaScript</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>render() {
  return (
    &lt;div className="video-scrubber">
      &lt;video
        src={"video.mp4"}
        muted={true}
        hidden={true}
        controls={false}        
        onSeeked={this.extractFrame} 
        ref={(element) => { this.videoElement = element }}>
      &lt;/video>

      &lt;div className="video-scrubber-frame-container"  
        ref={(element) => this.frameContainerElement = element}>
      &lt;/div>  
    &lt;/div>
  )    
}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #DCDCAA">render</span><span style="color: #D4D4D4">() {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> (</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #808080">&lt;</span><span style="color: #569CD6">div</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">className</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;video-scrubber&quot;</span><span style="color: #808080">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #808080">&lt;</span><span style="color: #569CD6">video</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">src</span><span style="color: #D4D4D4">=</span><span style="color: #569CD6">{</span><span style="color: #CE9178">&quot;video.mp4&quot;</span><span style="color: #569CD6">}</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">muted</span><span style="color: #D4D4D4">=</span><span style="color: #569CD6">{true}</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">hidden</span><span style="color: #D4D4D4">=</span><span style="color: #569CD6">{true}</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">controls</span><span style="color: #D4D4D4">=</span><span style="color: #569CD6">{false}</span><span style="color: #D4D4D4">        </span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">onSeeked</span><span style="color: #D4D4D4">=</span><span style="color: #569CD6">{this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">extractFrame</span><span style="color: #569CD6">}</span><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">ref</span><span style="color: #D4D4D4">=</span><span style="color: #569CD6">{</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">element</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> { </span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">videoElement</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">element</span><span style="color: #D4D4D4"> }</span><span style="color: #569CD6">}</span><span style="color: #808080">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #808080">&lt;/</span><span style="color: #569CD6">video</span><span style="color: #808080">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #808080">&lt;</span><span style="color: #569CD6">div</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">className</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;video-scrubber-frame-container&quot;</span><span style="color: #D4D4D4">  </span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">ref</span><span style="color: #D4D4D4">=</span><span style="color: #569CD6">{</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">element</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">frameContainerElement</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">element</span><span style="color: #569CD6">}</span><span style="color: #808080">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #808080">&lt;/</span><span style="color: #569CD6">div</span><span style="color: #808080">&gt;</span><span style="color: #D4D4D4">  </span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #808080">&lt;/</span><span style="color: #569CD6">div</span><span style="color: #808080">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">  )    </span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph"><strong>Create canvas representations of the video frames.</strong> Seek to one frame at a time using the known framerate of the video. The video component’s onSeeked event triggers the extractFrame function that draws the current video frame onto a canvas element.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">JavaScript</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>loadVideoFrames = () => {
  // Exit loop if desired number of frames have been extracted 
  if (this.frames.length >= frameCount){
    this.setState({
      visibleFrame = 0 
    })

    // Append all canvases to container div
    this.frames.forEach((frame) => {this.frameContainerElement.appendChild(frame)})
    return
  }

  // If extraction hasn’t started, set desired time for first frame 
  if (this.frames.length === 0){
    this.requestedTime = 0
  }
  else{
    this.requestedTime = this.requestedTime + this.frameTimestep
  }

  // Send seek request to video player for the next frame.
  this.videoElement.currentTime = this.requestedTime
}
 
 
extractFrame = () => {
  // Create DOM canvas object
  var canvas = document.createElement('canvas')
  canvas.className = "video-scrubber-frame"
  canvas.height = videoHeight
  canvas.width = videoWidth
      
  // Copy current frame to canvas
  var context = canvas.getContext('2d');
  context.drawImage(this.videoElement, 0, 0, videoWidth, videoHeight);  
  this.frames.push(canvas)

  //  Load the next frame
  loadVideoFrames()
}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #DCDCAA">loadVideoFrames</span><span style="color: #D4D4D4"> = () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #6A9955">// Exit loop if desired number of frames have been extracted </span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">frames</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">length</span><span style="color: #D4D4D4"> &gt;= </span><span style="color: #9CDCFE">frameCount</span><span style="color: #D4D4D4">){</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">setState</span><span style="color: #D4D4D4">({</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #9CDCFE">visibleFrame</span><span style="color: #D4D4D4"> = </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #D4D4D4">    })</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// Append all canvases to container div</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">frames</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">forEach</span><span style="color: #D4D4D4">((</span><span style="color: #9CDCFE">frame</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">frameContainerElement</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">appendChild</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">frame</span><span style="color: #D4D4D4">)})</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span></span>
<span class="line"><span style="color: #D4D4D4">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #6A9955">// If extraction hasn’t started, set desired time for first frame </span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">frames</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">length</span><span style="color: #D4D4D4"> === </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">){</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">requestedTime</span><span style="color: #D4D4D4"> = </span><span style="color: #B5CEA8">0</span></span>
<span class="line"><span style="color: #D4D4D4">  }</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">else</span><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">requestedTime</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">requestedTime</span><span style="color: #D4D4D4"> + </span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">frameTimestep</span></span>
<span class="line"><span style="color: #D4D4D4">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #6A9955">// Send seek request to video player for the next frame.</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">videoElement</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">currentTime</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">requestedTime</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #DCDCAA">extractFrame</span><span style="color: #D4D4D4"> = () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #6A9955">// Create DOM canvas object</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">canvas</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">document</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">createElement</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&apos;canvas&apos;</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #9CDCFE">canvas</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">className</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;video-scrubber-frame&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #9CDCFE">canvas</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">height</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">videoHeight</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #9CDCFE">canvas</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">width</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">videoWidth</span></span>
<span class="line"><span style="color: #D4D4D4">      </span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #6A9955">// Copy current frame to canvas</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">context</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">canvas</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">getContext</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&apos;2d&apos;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #9CDCFE">context</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">drawImage</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">videoElement</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">videoWidth</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">videoHeight</span><span style="color: #D4D4D4">);  </span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">frames</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">push</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">canvas</span><span style="color: #D4D4D4">)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #6A9955">//  Load the next frame</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #DCDCAA">loadVideoFrames</span><span style="color: #D4D4D4">()</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph"><strong>Define styling that will layer the canvases</strong> on top of each other.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">JavaScript</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>.video-scrubber-frame-container {
    position: relative;
}

.video-scrubber-frame {
    left: 0;
    position: absolute;
    top: 0;
}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">video</span><span style="color: #D4D4D4">-</span><span style="color: #9CDCFE">scrubber</span><span style="color: #D4D4D4">-</span><span style="color: #9CDCFE">frame</span><span style="color: #D4D4D4">-</span><span style="color: #9CDCFE">container</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C8C8C8">position</span><span style="color: #D4D4D4">: </span><span style="color: #9CDCFE">relative</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">video</span><span style="color: #D4D4D4">-</span><span style="color: #9CDCFE">scrubber</span><span style="color: #D4D4D4">-</span><span style="color: #9CDCFE">frame</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C8C8C8">left</span><span style="color: #D4D4D4">: </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C8C8C8">position</span><span style="color: #D4D4D4">: </span><span style="color: #9CDCFE">absolute</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C8C8C8">top</span><span style="color: #D4D4D4">: </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<h2 class="wp-block-heading" id="h-implement-scrubbing-functionality">Implement Scrubbing Functionality</h2>



<p class="wp-block-paragraph"><strong>Add mouse event listeners</strong> to handle scrubbing action. Here we create another canvas that will sit on top of all our frames to attach our listeners to.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">JavaScript</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>// Create mouseover canvas
var mouseEventCanvas = document.createElement('canvas')

// Set canvas attributes
mouseEventCanvas.className = "video-scrubber-frame"
mouseEventCanvas.height = videoHeight
mouseEventCanvas.width = videoWidth
mouseEventCanvas.onmousemove = this.onMouseDown
mouseEventCanvas.onmousedown = this.onMouseDown

// We set the z-index to be greater than that of the other frames
mouseEventCanvas.style&#91;'z-index'&#93; = 2

// Append to document
this.frameContainerElement.appendChild(mouseEventCanvas)</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">// Create mouseover canvas</span></span>
<span class="line"><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">mouseEventCanvas</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">document</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">createElement</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&apos;canvas&apos;</span><span style="color: #D4D4D4">)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// Set canvas attributes</span></span>
<span class="line"><span style="color: #9CDCFE">mouseEventCanvas</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">className</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;video-scrubber-frame&quot;</span></span>
<span class="line"><span style="color: #9CDCFE">mouseEventCanvas</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">height</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">videoHeight</span></span>
<span class="line"><span style="color: #9CDCFE">mouseEventCanvas</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">width</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">videoWidth</span></span>
<span class="line"><span style="color: #9CDCFE">mouseEventCanvas</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">onmousemove</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">onMouseDown</span></span>
<span class="line"><span style="color: #9CDCFE">mouseEventCanvas</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">onmousedown</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">onMouseDown</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// We set the z-index to be greater than that of the other frames</span></span>
<span class="line"><span style="color: #9CDCFE">mouseEventCanvas</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">style</span><span style="color: #D4D4D4">&#91;</span><span style="color: #CE9178">&apos;z-index&apos;</span><span style="color: #D4D4D4">&#93; = </span><span style="color: #B5CEA8">2</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// Append to document</span></span>
<span class="line"><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">frameContainerElement</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">appendChild</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">mouseEventCanvas</span><span style="color: #D4D4D4">)</span></span></code></pre></div>



<p class="wp-block-paragraph"><strong>Toggle z-index of visible canvases</strong> according to mouse positioning over the frames. For our scrubber, we are listening for a mousedown event that moves on the frames. As a user drags their mouse across the frames, we toggle the visible frame value stored in our React component state.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">JavaScript</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>onMouseDown = (event) => {
  // Bail early if we aren't clicking and dragging
  if (event.type === "mousemove" &amp;&amp; event.buttons === 0) {
    return 
  }

  event.preventDefault()
  
  const frameRect = this.mouseEventCanvas.getBoundingClientRect()
  const x = event.clientX - frameRect.left
  const y = event.clientY - frameRect.top

  if (event.buttons === 1){ // Left button down
    var frameRequested = Math.floor((x / frameRect.width) 
* this.fullResolutionFrames.length)      
    if (frameRequested !== this.state.visibleFrame &amp;&amp; frameRequested >= 0){
      this.setState({
        visibleFrame: frameRequested,
      })
    }
  }
}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #DCDCAA">onMouseDown</span><span style="color: #D4D4D4"> = (</span><span style="color: #9CDCFE">event</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #6A9955">// Bail early if we aren&apos;t clicking and dragging</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">event</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">type</span><span style="color: #D4D4D4"> === </span><span style="color: #CE9178">&quot;mousemove&quot;</span><span style="color: #D4D4D4"> &amp;&amp; </span><span style="color: #9CDCFE">event</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">buttons</span><span style="color: #D4D4D4"> === </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #D4D4D4">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #9CDCFE">event</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">preventDefault</span><span style="color: #D4D4D4">()</span></span>
<span class="line"><span style="color: #D4D4D4">  </span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">frameRect</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">mouseEventCanvas</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">getBoundingClientRect</span><span style="color: #D4D4D4">()</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">x</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">event</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">clientX</span><span style="color: #D4D4D4"> - </span><span style="color: #9CDCFE">frameRect</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">left</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">y</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">event</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">clientY</span><span style="color: #D4D4D4"> - </span><span style="color: #9CDCFE">frameRect</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">top</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">event</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">buttons</span><span style="color: #D4D4D4"> === </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">){ </span><span style="color: #6A9955">// Left button down</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">frameRequested</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">Math</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">floor</span><span style="color: #D4D4D4">((</span><span style="color: #9CDCFE">x</span><span style="color: #D4D4D4"> / </span><span style="color: #9CDCFE">frameRect</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">width</span><span style="color: #D4D4D4">) </span></span>
<span class="line"><span style="color: #D4D4D4">* </span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">fullResolutionFrames</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">length</span><span style="color: #D4D4D4">)      </span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">frameRequested</span><span style="color: #D4D4D4"> !== </span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">state</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">visibleFrame</span><span style="color: #D4D4D4"> &amp;&amp; </span><span style="color: #9CDCFE">frameRequested</span><span style="color: #D4D4D4"> &gt;= </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">){</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">setState</span><span style="color: #D4D4D4">({</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">visibleFrame:</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">frameRequested</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">      })</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">  }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph">We <strong>check for a changed visibleFrame value</strong> in the React component lifecycle and change the z-indexes of the appropriate frames.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">JavaScript</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>componentWillUpdate(nextProps, nextState){
  // set the visible frame
  if (nextState.visibleFrame !== this.state.visibleFrame){
    if (this.state.visibleFrame &lt; this.frames.length){
      this.frames&#91;this.state.visibleFrame&#93;.style&#91;'z-index'&#93; = 0 
    }   
    if (nextState.visibleFrame &lt; this.frames.length){   
      this.frames&#91;nextState.visibleFrame&#93;.style&#91;'z-index'&#93; = 1 
    }
  }
}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #DCDCAA">componentWillUpdate</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">nextProps</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">nextState</span><span style="color: #D4D4D4">){</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #6A9955">// set the visible frame</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">nextState</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">visibleFrame</span><span style="color: #D4D4D4"> !== </span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">state</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">visibleFrame</span><span style="color: #D4D4D4">){</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">state</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">visibleFrame</span><span style="color: #D4D4D4"> &lt; </span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">frames</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">length</span><span style="color: #D4D4D4">){</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">frames</span><span style="color: #D4D4D4">&#91;</span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">state</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">visibleFrame</span><span style="color: #D4D4D4">&#93;.</span><span style="color: #9CDCFE">style</span><span style="color: #D4D4D4">&#91;</span><span style="color: #CE9178">&apos;z-index&apos;</span><span style="color: #D4D4D4">&#93; = </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #D4D4D4">    }   </span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">nextState</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">visibleFrame</span><span style="color: #D4D4D4"> &lt; </span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">frames</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">length</span><span style="color: #D4D4D4">){   </span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">frames</span><span style="color: #D4D4D4">&#91;</span><span style="color: #9CDCFE">nextState</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">visibleFrame</span><span style="color: #D4D4D4">&#93;.</span><span style="color: #9CDCFE">style</span><span style="color: #D4D4D4">&#91;</span><span style="color: #CE9178">&apos;z-index&apos;</span><span style="color: #D4D4D4">&#93; = </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">  }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph">There you have it! A simple video scrubber in a client browser.</p>



<p class="wp-block-paragraph"><strong><a href="https://static.dmcinfo.com/services/application-development/web-application-development">Learn more about DMC&#8217;s W</a></strong><a href="https://static.dmcinfo.com/services/application-development/web-application-development"><strong>eb Application Development services.</strong></a></p>
<p>The post <a href="https://static.dmcinfo.com/blog/23297/frame-accurate-video-scrubbing-in-the-client/">Frame Accurate Video Scrubbing in the Client</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Creating a Password Protected SDF File from an Existing SQL Database</title>
		<link>https://static.dmcinfo.com/blog/24119/creating-a-password-protected-sdf-file-from-an-existing-sql-database/</link>
		
		<dc:creator><![CDATA[DMC]]></dc:creator>
		<pubDate>Mon, 10 Jul 2017 11:30:18 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[MS Visual Studio/.NET]]></category>
		<category><![CDATA[Software Development]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/24119/creating-a-password-protected-sdf-file-from-an-existing-sql-database/</guid>

					<description><![CDATA[<p>SQL Server Compact Edition is a&#160;compact&#160;relational database&#160;produced by&#160;Microsoft&#160;for applications that run on mobile devices and desktops.&#160;Embedding these databases into a Windows&#160;application in a portable file-oriented format can be very useful.&#160; While working&#160;on a recent Windows application, DMC wanted to add an extra layer of security to our application by protecting our SQL CE database files [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/24119/creating-a-password-protected-sdf-file-from-an-existing-sql-database/">Creating a Password Protected SDF File from an Existing SQL Database</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">SQL Server Compact Edition is a&nbsp;compact&nbsp;relational database&nbsp;produced by&nbsp;Microsoft&nbsp;for applications that run on mobile devices and desktops.&nbsp;Embedding these databases into a Windows&nbsp;application in a portable file-oriented format can be very useful.&nbsp;</p>



<p class="wp-block-paragraph">While working&nbsp;on a recent Windows application, DMC wanted to add an extra layer of security to our application by protecting our SQL CE database files with a password.&nbsp;Although the process of creating a&nbsp;“.SDF” file from an existing database is simple, there are a few additional steps that are required when adding password protection.&nbsp;</p>



<p class="wp-block-paragraph">After finding no good resources on this process anywhere on the internet, I decided to document the process here.</p>



<p class="wp-block-paragraph">This walkthrough will use the SQL Server Compact Toolbox for Runtime 4.0 which <a href="https://marketplace.visualstudio.com/items?itemName=ErikEJ.SQLServerCompactSQLiteToolbox" type="link" id="https://marketplace.visualstudio.com/items?itemName=ErikEJ.SQLServerCompactSQLiteToolbox">you can download</a>.</p>



<h2 id="h-step-1-create-an-empty-password-protected-sdf-file" class="wp-block-heading">Step 1: Create an empty, password protected .SDF file</h2>



<p class="wp-block-paragraph">Right click&nbsp;on <strong>No SQL Compact Data Connections Found</strong>&nbsp;and select&nbsp;<strong>Add SQL Server Compact 4.0 Connection…</strong></p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Create-New-SDF-File-1_1.jpg" alt="Create new .SDF file "/></figure>



<p class="wp-block-paragraph">A small window will pop up&nbsp;where you will enter your desired password.&nbsp;After your password has been entered, click <strong>Create</strong>&nbsp;at the top of the window where you will name your new .SDF file.&nbsp;</p>



<p class="wp-block-paragraph">Finally, click <strong>Close</strong>&nbsp;at the bottom of the window in order for your new empty .SDF to be created.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Create-New-SDF-File-2_1.jpg" alt="Assign .SDF file password"/></figure>



<p class="wp-block-paragraph">Your password protected .SDF file will now appear on the left-hand side in the main window of the toolbox.&nbsp;</p>



<h2 id="h-step-2-export-your-existing-sql-server-database-to-a-sqlce-file" class="wp-block-heading">Step 2: Export your existing SQL Server Database to a .SQLCE file.</h2>



<p class="wp-block-paragraph">Right click on <strong>SQL Server Compact Data Connections</strong>&nbsp;and select <strong>Script SQL Server Database Schema and Data…</strong></p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Export-From-SQL-Server-to-sqlce_1.jpg" alt="Export SQL database to .SQLCE "/></figure>



<p class="wp-block-paragraph">A window will popup that requires you to enter information to connect to your existing SQL Server DB.&nbsp;</p>



<p class="wp-block-paragraph">Enter the <strong>server name</strong> and select the <strong>database name</strong> from the drop-down menu.&nbsp;</p>



<p class="wp-block-paragraph">Finally, click <strong>Ok</strong>&nbsp;and name your new .SQLCE file.&nbsp;</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Export-From-SQL-Server-to-sqlce-2_1.jpg" alt="Export existing SQL Server database to SQLCE"/></figure>



<p class="wp-block-paragraph">In the next popup, select the&nbsp;tables from your existing database which you want to export by clicking the appropriate check boxes. This will vary based on your application.&nbsp;</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Export-From-SQL-Server-to-sqlce-3_1.jpg" alt="Select tables to export to .SDF"/></figure>



<h2 id="h-step-3-move-the-exported-data-into-your-new-password-protected-sdf" class="wp-block-heading">Step 3: Move the exported data into your new password protected SDF.</h2>



<p class="wp-block-paragraph">Next, right-click on your new password protected DB that has been created on the left side of the toolbox and select <strong>Open SQL Editor</strong>”.&nbsp;</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Import-SQL-Data-Into-SDF-File_1.jpg" alt="Import SQL data from SQLCE file"/></figure>



<p class="wp-block-paragraph">An editor will open&nbsp;up on the main part of the screen.</p>



<p class="wp-block-paragraph">Select <strong>Open</strong>&nbsp;and navigate to the location of the .SQLCE file you just created.</p>



<p class="wp-block-paragraph">&nbsp;</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Import-SQL-Data-Into-SDF-File-2_1.jpg" alt="Navigate to existing SQLCE file"/></figure>



<p class="wp-block-paragraph">Once this step is completed, you will see text commands opened in the main window.&nbsp;</p>



<p class="wp-block-paragraph">Click <strong>Execute</strong>&nbsp;and wait for this operation to complete.&nbsp;Once completed, you will be able to verify the operation was successful by expanding <strong>Tables</strong>&nbsp;in the left-hand side tree view and checking that the correct tables have been added.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Import-SQL-Data-Into-SDF-File-3_1.jpg" alt="Execute operation and verify populated .SDF file"/></figure>



<p class="wp-block-paragraph">SQL Server Database has now successfully been moved into a password protected .SDF file!</p>



<p class="wp-block-paragraph">As a final note, when using this in your Windows application you must enter the .SDF’s password. Microsoft provides information about <a href="https://msdn.microsoft.com/en-us/library/ms171741(v=SQL.105).aspx" type="link" id="https://msdn.microsoft.com/en-us/library/ms171741(v=SQL.105).aspx">how to accomplish this</a>. </p>



<p class="wp-block-paragraph"><strong><a href="https://static.dmcinfo.com/services/embedded-development-and-embedded-programming" target="_blank">Learn more about DMC&#8217;s Custom Software &amp; Hardware development services.</a>&nbsp;</strong></p>
<p>The post <a href="https://static.dmcinfo.com/blog/24119/creating-a-password-protected-sdf-file-from-an-existing-sql-database/">Creating a Password Protected SDF File from an Existing SQL Database</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Setting Up Docker for WordPress Development</title>
		<link>https://static.dmcinfo.com/blog/24644/setting-up-docker-for-wordpress-development/</link>
		
		<dc:creator><![CDATA[DMC]]></dc:creator>
		<pubDate>Tue, 28 Feb 2017 12:17:31 +0000</pubDate>
				<category><![CDATA[Application Development]]></category>
		<category><![CDATA[PC Application Development]]></category>
		<category><![CDATA[Web Application Development]]></category>
		<category><![CDATA[HTML and CSS]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Web]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/24644/setting-up-docker-for-wordpress-development/</guid>

					<description><![CDATA[<p>Way back when in 2014, I wrote a blog about setting up WordPress on IIS. At that time, Docker was only a year old and I hadn&#8217;t even heard of it.&#160;It&#8217;s now 2017&#160;and things are different. Docker has matured and has gained enormous popularity for making developers&#8217; lives easier. One of Docker&#8217;s uses we&#8217;ll examine [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/24644/setting-up-docker-for-wordpress-development/">Setting Up Docker for WordPress Development</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Way back when in 2014, I wrote a blog about setting up <a href="https://static.dmcinfo.com/latest-thinking/blog/id/8808/how-to-install-wordpress-on-an-iis-server" target="_blank">WordPress on IIS</a>. At that time, Docker was only a year old and I hadn&#8217;t even heard of it.&nbsp;It&#8217;s now 2017&nbsp;and things are different. Docker has matured and has gained enormous popularity for making developers&#8217; lives easier. One of Docker&#8217;s uses we&#8217;ll examine today&nbsp;is using Docker for development, particularly web development in WordPress. First, let&#8217;s have a little Q&amp;A session and then we&#8217;ll jump right in!</p>



<h2 class="wp-block-heading" id="h-what-the-heck-is-docker">What the Heck is Docker?</h2>



<p class="wp-block-paragraph">Docker acts very much like VirtualBox or VMware, but stripped down and more single-purposed. It runs tiny Linux&nbsp;VMs that are &#8220;snapshots&#8221; of applications with all the setup already completed for you (Windows VMs are actually supported now, too).&nbsp;</p>



<h2 class="wp-block-heading" id="h-why-is-docker-useful">Why is Docker Useful?</h2>



<p class="wp-block-paragraph">Using Docker&#8217;s extensive repository of prebuilt images, one can really quickly and easily get a variety of applications running on their system. Without Docker, there&#8217;s usually a good amount of setup that must be done for any given application, such as WordPress or MySQL. With Docker, it only takes&nbsp;a few commands to get going. Beyond this, Docker can also be used to automate the setup/teardown of different software configurations &#8211; which is what we&#8217;ll be doing today.</p>



<h2 class="wp-block-heading" id="h-why-use-docker-for-development">Why use Docker for Development?</h2>



<p class="wp-block-paragraph">Developers work with a lot of different technologies, languages, and system configurations. If one were to install all of the various servers, databases, languages, runtimes, and applications on their host machine, there&#8217;s bound to be a conflict somewhere: a port being used by another application, resources being used when switching from one type of a development to another, etc. Since Docker is a self-contained environment, your host machine is not modified and things are much less likely to break because of the aforementioned issues.</p>



<h2 class="wp-block-heading" id="h-getting-started">Getting Started</h2>



<p class="wp-block-paragraph">Alright, enough questions!&nbsp;Let&#8217;s get started setting up Docker with WordPress and MySQL. This can aid in development because the container(s) we create can be shared between developers.</p>



<p class="wp-block-paragraph">Depending on your host machine, the setup instructions for Docker vary. All of my development was using Linux (specifically Ubuntu MATE 16.04.2 LTS).&nbsp;</p>



<ol class="wp-block-list">
<li>First things first, install Docker. Docker&#8217;s documentation is quite good, so <a href="https://docs.docker.com/get-started/" target="_blank" rel="noreferrer noopener">take a look</a> and then continue on.</li>



<li>We&#8217;ll also be using something called Docker Compose which lets you easily setup and link multiple containers. Windows and Mac users should install <a href="https://www.docker.com/products/docker-toolbox" target="_blank">Docker Toolbox</a>, while Linux users should <a href="https://docs.docker.com/compose/install/" target="_blank">follow the instructions here</a>.</li>



<li>Once that&#8217;s done, it&#8217;s smooth sailing. Create a directory where you want your WordPress and MySQL database to live. Create a file named docker-compose.yml and paste the following inside:
 <pre>version: '3'

services:
   db:
     image: mysql:5.7
     volumes:
       - ./data/mysql:/var/lib/mysql
     ports:
       - "3306:3306"
     restart: always
     environment:
       MYSQL_ROOT_PASSWORD: wordpress
       MYSQL_DATABASE: wordpress
       MYSQL_USER: wordpress
       MYSQL_PASSWORD: wordpress

   wordpress:
     depends_on:
       - db
     image: wordpress:latest
     volumes:
       - ./data/wordpress:/var/www/html
     ports:
       - "8000:80"
     restart: always
     environment:
       WORDPRESS_DB_HOST: db:3306
       WORDPRESS_DB_PASSWORD: wordpress
</pre>
 </li>



<li>Save the file. This file describes the Docker images (mysql:5.7 and wordpress:latest) as well as where each of these images will store their data, and on what ports one can access them.&nbsp;</li>



<li>Now let the magic happen.&nbsp;Open a terminal window where you created your docker-compose.yml file and type docker-compose up -d (the -d switch tells docker-compose to run in the background).</li>



<li>Open up a browser window, navigate to https://static.dmcinfo.com/ and you should be presented with the WordPress setup screen!</li>



<li>Congrats. You&#8217;ve just used Docker to setup a development environment that you can assemble and disassemble within minutes. Get hacking!</li>
</ol>



<h2 class="wp-block-heading" id="h-what-s-next">What&#8217;s Next?</h2>



<p class="wp-block-paragraph">Since this post was solely about setting up Docker for WordPress development, I&#8217;ve barely scratched the surface of all of the cool things Docker can do or how it can be used beyond just the development phase. If you&#8217;d like to see a particular post about Docker, let me know in the comments!</p>



<p class="wp-block-paragraph">It&#8217;s also worth mentioning that there&#8217;s other software that shares&nbsp;the same space of Docker (containerization, virtualization, etc.). One particularly interesting software&nbsp;is Vagrant which essentially manages your Docker containers (or VirtualBox, VMWare, or even Amazon EC2 VMs). Vagrant can be used for&nbsp;provisioning (setting up VMs and handling configuration), and makes rapid deployment painless.&nbsp;</p>



<p class="wp-block-paragraph">I encourage you to explore further: <a href="https://github.com/veggiemonk/awesome-docker">Docker</a>, <a href="https://github.com/iJackUA/awesome-vagrant">Vagrant</a></p>



<p class="wp-block-paragraph"><a href="https://static.dmcinfo.com/services/application-development/web-application-development"><strong>Learn more about DMC&#8217;s web application development services.&nbsp;</strong></a></p>
<p>The post <a href="https://static.dmcinfo.com/blog/24644/setting-up-docker-for-wordpress-development/">Setting Up Docker for WordPress Development</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>BlueGecko BGScript Development with VScode</title>
		<link>https://static.dmcinfo.com/blog/24770/bluegecko-bgscript-development-with-vscode/</link>
		
		<dc:creator><![CDATA[DMC]]></dc:creator>
		<pubDate>Tue, 10 Jan 2017 11:48:13 +0000</pubDate>
				<category><![CDATA[Application Development]]></category>
		<category><![CDATA[IoT]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Software Development]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/24770/bluegecko-bgscript-development-with-vscode/</guid>

					<description><![CDATA[<p>This tutorial will outline the process to configure Visual Studio Code for developing Blue Gecko script code. It assumes you have some familiarity with the BlueGecko scripting language. If not, check out the developer guide. Blue Gecko scripting is a high level programming language designed for the Silicon Labs line of Blue Gecko Bluetooth modules. Installation Configure Tools [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/24770/bluegecko-bgscript-development-with-vscode/">BlueGecko BGScript Development with VScode</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">This tutorial will outline the process to configure Visual Studio Code for developing Blue Gecko script code. It assumes you have some familiarity with the BlueGecko scripting language. If not, check out the <a href="https://www.silabs.com/documents/public/user-guides/ug209-bgscript-scripting-language.pdf" target="_blank" rel="noreferrer noopener">developer guide</a>. Blue Gecko scripting is a high level programming language designed for the Silicon Labs line of Blue Gecko Bluetooth modules.</p>



<h2 class="wp-block-heading" id="h-installation">Installation</h2>



<ol class="wp-block-list">
<li>Download and install the BLE <a href="http://www.silabs.com/products/wireless/bluetooth/bluetooth-smart-modules/Pages/bluegiga-bluetooth-smart-software-stack.aspx" target="_blank">SDK</a> and the <a href="http://www.silabs.com/products/wireless/bluetooth/bluetooth-smart-modules/Pages/bluegiga-bluetooth-smart-software-stack.aspx" target="_blank">BLE Update Tool</a> using the default location and agree&nbsp;to licenses.&nbsp;

 

 
 
<p class="wp-block-paragraph">These installs provide&nbsp;the complier and some example code as well as the download tool to push the compiled code to the Bluetooth chip. Wait to restart your system until you have completed the next step of installing Visual Studio Code.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/BGS-Blog-Download-Page.png" alt="Screenshot of download page "/></figure>
</li>



<li>Download and install <a href="https://code.visualstudio.com/download">Visual Studio Code</a> using the default location and agree&nbsp;to licenses.&nbsp;
 

 
 
<p class="wp-block-paragraph">I recommend selecting <strong>Add &#8220;Open with Code&#8221; action to Windows Explorer file context menu </strong>and <strong>Add &#8220;Open with Code&#8221; action to Windows Explorer directory context menu</strong> from the list of Additional Tasks. This will provide quick right-click functionality to open our BGScript project later.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/BGS-Blog-VSCode-Config.png" alt="Screenshot of Setup Configuration for Visual Studio Code"/></figure>
</li>



<li>Restart your system now so that the BLE SDK, the BLE Update Tool, and Visual Studio Code can finish their installations.&nbsp;</li>
</ol>



<h2 class="wp-block-heading" id="h-configure-tools">Configure Tools</h2>



<p class="wp-block-paragraph">Now that all our tools are installed, let’s configure VScode so that we can compile and download our BGScript code straight from the editor.&nbsp;</p>



<ol class="wp-block-list">
<li>Open Windows explorer, and navigate to:&nbsp;
 

 

 
 
<p class="wp-block-paragraph"><strong><span style="font-family: courier new;">C:\Bluegiga\ble-1.4.2-130\example\&lt;your device&gt;\bgdemo&nbsp;</span></strong></p>



<p class="wp-block-paragraph">If you didn&#8217;t use the default location for the BLE SDK, or if the version of the SDK has been updated, your path will be different. I&#8217;m using the BLE113, so my path is:</p>



<p class="wp-block-paragraph"><strong><span style="font-family: courier new;">C:\Bluegiga\ble-1.4.2-130\example\dkble113\bgdemo</span></strong></p>
</li>



<li>Right click in the window and select <strong>Open with Code</strong>. This will open all of the files in the folder in a new instance of VScode.&nbsp;
 
 
<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/BGS-Blog-Open-With-Code.png" alt="Screenshot of Windows Explorer, Open with Code menu selection"/></figure>
</li>



<li>In VScode, type the hot key <strong>Ctrl+Shift+P</strong> to open the Command Palette, and then type <strong>Task </strong>to bring up the options with the keyword &#8220;Task&#8221;.
 
 
<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/BGS-Blog-Configure-Task-Runner.png" alt="Visual Studio Code Command Palette - selecting Tasks: Configure Task Runner"/></figure>
</li>



<li>Select <strong>Tasks: Configure Task Runner</strong>. This opens some of the defaults tasks in VSCode, but we want to create a custom one, so select <strong>Others</strong>. This will create a .vscode folder in our working directory with a tasks.json file.&nbsp;
 

 

 
 
<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/BGS-Blog-Select-Other-Task.png" alt="Selecting Others in the Visual Studio Code Command Palette "/></figure>



<p class="wp-block-paragraph">The task.json defines all the parameters and functionality of the task. It is configured by default to print &#8220;Hello World&#8221; to the terminal in VScode.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/BGS-Blog-Hello-World.png" alt="Visual Studio Code display output of &quot;Hello World&quot;"/></figure>
</li>



<li>Type <strong>Ctrl+Shift+B</strong>. This will run our new task, and you should see the terminal open in VScode and display &#8220;Hello World&#8221;
 
 
<p class="wp-block-paragraph">We&#8217;ll update this task to compile our BGScript software instead of the default functionality when we type Ctrl+Shift+B. Since we&#8217;ll also need a task to download the compiled hex file to the Bluetooth module, we&#8217;ll need to modify this single task to handle multiple tasks.&nbsp;</p>
</li>



<li>Download the attached task.json file and replace your current tasks.json file. With this new file, instead of calling the &#8216;echo&#8217; command, we&#8217;ll call the Windows ‘cmd’ command and pass it different executables and files based on which task we want to run.&nbsp;</li>
</ol>



<h2 class="wp-block-heading" id="h-running-tasks">Running Tasks</h2>



<p class="wp-block-paragraph">For the top level ‘args’, we use /C as a placeholder for the actual arguments we&#8217;ll pass based on the task we want to run. Each task inside the main task has an arbitrary name and arguments to pass back to the cmd command.&nbsp;</p>



<ol class="wp-block-list">
<li>Pass the first task, defined as <strong>Build</strong>

 
 
<p class="wp-block-paragraph">The <strong><span style="font-family: courier new;">&#8220;isBuildCommand&#8221;: true</span></strong> tells VScode that if we type Ctrl+Shift+B, it should run this specific task. There are a few other hot key tasks, but this is the only one we&#8217;ll use.&nbsp;</p>
</li>



<li>Pass the next task, defined as <strong>Download</strong>. This task will download the compiled code to the module.&nbsp;</li>



<li><strong>Remember to change the path if you didn&#8217;t keep the default installation directory.&nbsp;</strong>
 
 
<p class="wp-block-paragraph">Looking back at the args for the Build command, we can see that it will call the bgbuild executable that was installed with the SDK.</p>
</li>



<li><strong>Make sure you don&#8217;t have multiple BGScript projects in a single directory.&nbsp;</strong></li>
</ol>



<p class="wp-block-paragraph">When the bgbuild.exe is called, it expects a bgproj file that it will compile. The *.bgproj gets the first bgproj file from the working directory.</p>



<h3 class="wp-block-heading" id="h-download-task">Download Task</h3>



<p class="wp-block-paragraph">The args for the Download task are in the&nbsp;command line update tool (bleupdate-cli.exe), which was part of the SDK installation.&nbsp;</p>



<p class="wp-block-paragraph">The bleupdate-cli.exe takes a command, (list, update, get, set) as its first argument. Since we want to update the module, we&#8217;ll pass &#8216;update&#8217; as the command and pass the compiled hex&nbsp;file which was created from our Build task.&nbsp;</p>



<p class="wp-block-paragraph"><strong>Again, make sure there is only a single .hex file in the working directory to ensure we&#8217;re downloading the correct hex file</strong>.&nbsp;</p>



<h3 class="wp-block-heading" id="h-viewing-the-output">Viewing the Output</h3>



<p class="wp-block-paragraph">The last task combines both features into a single task that will build the project and then immediately download it to the Bluetooth module.</p>



<p class="wp-block-paragraph">Now, if you type <strong>Ctrl+Shift+B</strong>, you should see the output of bgbuild.exe for the demo application that we&#8217;re working with.&nbsp;</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/BGS-Blog-bgbuild.png" alt="Visual Studio Code bgbuild.exe output"/></figure>



<ol class="wp-block-list">
<li>Type <strong>Ctrl+Shift+P</strong> to download the hex file so we can run the task from the command palette, then type <strong>Tasks: Run Task</strong> and click <strong>Enter</strong>. You&#8217;ll then see a list of the three tasks that we have defined.&nbsp;</li>



<li>Select <strong>Download</strong> to download the already compiled hex file, or select <strong>Build &amp; Download</strong> to recompile the project before downloading.&nbsp;</li>
</ol>



<h3 class="wp-block-heading" id="h-keybinding-shortcut">Keybinding Shortcut</h3>



<p class="wp-block-paragraph">Now we can quickly compile our BGScript project with <strong>Ctrl+Shift+B</strong>, but it&#8217;s quite a bit of typing to run the other tasks, so let’s create a quick key binding shortcut so that when we press the F6 key, we&#8217;ll immediately be presented with our available tasks, and then we can select the one we want.</p>



<ol class="wp-block-list">
<li>Open the command palette again with <strong>Ctrl+Shift+P</strong> and type <strong>Keyboard</strong>. The only option should be <strong>Preferences: Open Keyboard Shortcuts.</strong>&nbsp;Select it, and two files should open next to each other.

 
 
<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/BGS-Blog-Keybinding.png" alt="Visual Studio Code Command Palette - selecting open keyboard shortcuts"/></figure>
</li>



<li>In the keybindings.json file on the right, enter <strong><span style="font-family: courier new;">{&#8220;key&#8221;: &#8220;f6&#8221;, &#8220;command&#8221;: &#8220;workbench.action.tasks.runTask&#8221;}</span></strong> inside the square brackets.</li>



<li>Save the keybindings.json and close it. Close the Default Keyboard Shortcuts file as well.</li>
</ol>



<p class="wp-block-paragraph">Pressing F6 will now open the command palette with our available tasks available to select.</p>



<p class="wp-block-paragraph">Now that VScode functions more like an IDE rather than a basic text editor, in the next blog I&#8217;ll go through setting up text highlighting to make development easier.</p>



<p class="wp-block-paragraph">Learn more about&nbsp;<a href="/services/embedded-development-and-embedded-programming">DMC&#8217;s Custom Software and Hardware Services</a>.</p>
<p>The post <a href="https://static.dmcinfo.com/blog/24770/bluegecko-bgscript-development-with-vscode/">BlueGecko BGScript Development with VScode</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Using Segger Real Time Transfer with an EFM32</title>
		<link>https://static.dmcinfo.com/blog/24890/using-segger-real-time-transfer-with-an-efm32/</link>
		
		<dc:creator><![CDATA[DMC]]></dc:creator>
		<pubDate>Fri, 18 Nov 2016 12:53:56 +0000</pubDate>
				<category><![CDATA[Embedded Development & Programming]]></category>
		<category><![CDATA[Software Development]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/24890/using-segger-real-time-transfer-with-an-efm32/</guid>

					<description><![CDATA[<p>Today, I want to detail a couple of cool tricks to use Segger Real Time Transfer with an EFM32 to create an easy-to-view trace log.&#160;Segger Real Time Transfer, or RTT for short, is a debugging interface designed&#160;specifically around the J-Links capabilities&#160;to provide an extremely efficient debug message input and output interface.&#160; This is accomplished by [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/24890/using-segger-real-time-transfer-with-an-efm32/">Using Segger Real Time Transfer with an EFM32</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Today, I want to detail a couple of cool tricks to use Segger Real Time Transfer with an EFM32 to create an easy-to-view trace log.&nbsp;Segger Real Time Transfer, or RTT for short, is a debugging interface designed&nbsp;specifically around the J-Links capabilities&nbsp;to provide an extremely efficient debug message input and output interface.&nbsp;</p>



<p class="wp-block-paragraph">This is accomplished by writing messages to a RAM buffer on the microcontroller that the J-Link is capable of reading through the standard ARM debug interface.&nbsp;This means that RTT requires a low-performance overhead (essentially a memcopy) and does not interfere with the execution of a user program.&nbsp;Additional details about implementation and performance can be found on SEGGER’s <a href="https://www.segger.com/jlink-rtt.html">website</a>.</p>



<h2 id="h-nbsp" class="wp-block-heading">&nbsp;</h2>



<h2 id="h-project-integration" class="wp-block-heading">Project Integration</h2>



<p class="wp-block-paragraph">In order to integrate RTT into a project,&nbsp;you simply need to copy the relevant source files and include them in your project.&nbsp;These files can be found in the J-Link Software and Documentation Pack under Samples\RTT\RTT.&nbsp;At a minimum, the following files are required:</p>



<ul class="wp-block-list">
<li>SEGGER_RTT.h</li>



<li>SEGGER_RTT.c</li>



<li>SEGGER_RTT _Conf.c</li>
</ul>



<p class="wp-block-paragraph">Optionally, a user can include:</p>



<ul class="wp-block-list">
<li>SEGGER_RTT _printf.c (adds lightweight printf support to protocol)</li>



<li>SEGGER_RTT_syscalls_X.c (overrides system calls for X compiler)</li>
</ul>



<p class="wp-block-paragraph">Once copied into the project, you can configure the system for your specific use case, or leave it to its defaults and simply use the standard SEGGER_RTT_Read(), SEGGER_RTT_Write(), and SEGGER_RTT_printf() functions.&nbsp;There are several configuration options and additional features available that are out of the scope of this article and are well documented on SEGGER’s website and in the source files.</p>



<h2 id="h-running-rtt-terminal" class="wp-block-heading">Running RTT Terminal</h2>



<p class="wp-block-paragraph">Your debug outputs can be viewed in several ways once your code is compiled and running.&nbsp;The simplest way&nbsp;is to open the J-Link RTT Viewer application installed on your computer and select&nbsp;Existing Session.&nbsp;This will connect you to your current active debug session and begin collecting messages.</p>



<p class="wp-block-paragraph">&nbsp; &nbsp;&nbsp;</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/image005.png" alt="Screenshot of RTT Viewer Output"/></figure>



<p class="wp-block-paragraph">Note: For EFM32 kits, you must start the RTTViewer prior to initiating a debug session</p>



<h2 id="h-logging-with-realterm" class="wp-block-heading">Logging with RealTerm</h2>



<p class="wp-block-paragraph">Once you have the RTT viewer displaying messages, the next step is to log those messages to a file. We are going to accomplish this by utilizing RTT’s available telnet connection. You can connect a Telnet client to localhost:19021 whenever RTT is running. In this case, we will use the <a href="https://sourceforge.net/projects/realterm/" type="link" id="https://sourceforge.net/projects/realterm/">application RealTerm</a>. Once RealTerm is installed, open it, connect to localhost:19021, and then begin capturing information to a log file.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/image007.png" alt="Screenshot of the Realterm Configuration"/></figure>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/image009.png" alt="Realterm Configuration 2"/></figure>



<p class="wp-block-paragraph">Note: Depending on the debugger and IDE used, RTT may not start on its own, and you will need to open the RTT Viewer application prior to connecting over Telnet.</p>



<p class="wp-block-paragraph">&nbsp;</p>



<h2 id="h-viewing-with-baretail" class="wp-block-heading">Viewing with Baretail</h2>



<p class="wp-block-paragraph">The last trick I want to show off is the ability to view the above log files in real-time. This can be done using the <a href="https://www.baremetalsoft.com/baretail/" type="link" id="https://www.baremetalsoft.com/baretail/">application BareTail</a>, which allows you to view text files in real-time as they are being edited and also highlight specific messages or characters.</p>



<p class="wp-block-paragraph">&nbsp;</p>



<p class="wp-block-paragraph">&nbsp;</p>



<h2 id="h-comparison-to-uart-and-j-link-debugger" class="wp-block-heading">Comparison to UART and J-Link debugger</h2>



<p class="wp-block-paragraph">Finally, we can compare the use of RTT to other standard debugging practices such as a dedicated UART or debugging with breakpoints by looking at each option&#8217;s pros.</p>



<p class="wp-block-paragraph"><strong>Segger RTT:</strong></p>



<ul class="wp-block-list">
<li>Low overhead</li>



<li>No additional pins/connections to MCU</li>



<li>Simple to implement</li>



<li>Doesn’t alter program flow</li>
</ul>



<p class="wp-block-paragraph"><strong>Dedicated UART:</strong></p>



<ul class="wp-block-list">
<li>Doesn’t require an exposed debug connection and J-link hardware</li>



<li>Doesn’t alter program flow</li>
</ul>



<p class="wp-block-paragraph"><strong>Breakpoints:</strong></p>



<ul class="wp-block-list">
<li>No additional pins/connections to MCU</li>



<li>Provides complete information (call stack, variable values, execution order)</li>
</ul>



<p class="wp-block-paragraph"><a href="https://static.dmcinfo.com/services/embedded-development-and-embedded-programming"><strong>Learn more about DMC’s Embedded Development and Programming&nbsp;expertise.</strong></a></p>
<p>The post <a href="https://static.dmcinfo.com/blog/24890/using-segger-real-time-transfer-with-an-efm32/">Using Segger Real Time Transfer with an EFM32</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>The Revit API: Creating Your First Add-In</title>
		<link>https://static.dmcinfo.com/blog/24963/the-revit-api-creating-your-first-add-in/</link>
		
		<dc:creator><![CDATA[Christopher Olsen]]></dc:creator>
		<pubDate>Thu, 03 Nov 2016 08:17:01 +0000</pubDate>
				<category><![CDATA[Application Development]]></category>
		<category><![CDATA[MS Visual Studio/.NET]]></category>
		<category><![CDATA[Software Development]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/24963/the-revit-api-creating-your-first-add-in/</guid>

					<description><![CDATA[<p>Lately, I&#8217;ve gotten reacquainted with an old friend of mine: the Revit API. Revit is an incredible piece of architectural software from Autodesk, and one of its features is the ability to expand its functionality through the use of add-ins. Revit add-in development is now one of the many services that we&#8217;re able to offer [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/24963/the-revit-api-creating-your-first-add-in/">The Revit API: Creating Your First Add-In</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Lately, I&#8217;ve gotten reacquainted with an old friend of mine: the Revit API. Revit is an incredible piece of architectural software from Autodesk, and one of its features is the ability to expand its functionality through the use of add-ins. Revit add-in development is now one of the many services that we&#8217;re able to offer here at DMC, and I&#8217;d like to celebrate that fact by sharing an article about how to get started with Revit add-in development.</p>



<p class="wp-block-paragraph">First of all, this article assumes you know/have the following things:</p>



<ol class="wp-block-list">
<li>Intermediate C# and .NET development experience or knowledge</li>



<li>A license for Revit (preferably 2013 or later) so you can actually test your add-in</li>



<li>A license for Visual Studio (I&#8217;ll be using 2015 for this example). You can develop Revit macros using Revit’s built-in code editor, but developing add-ins (external commands and external applications) pretty much requires Visual Studio.</li>
</ol>



<p class="wp-block-paragraph">The first thing you&#8217;ll want to do is set up your development machine. I chose to use a virtual machine (VM) running Windows 8, for reasons that are beyond the scope of this article. Make sure you check the system requirements for the version of Revit that you&#8217;re developing for. Install Revit and your chosen version of Visual Studio, and you&#8217;re ready to get started.</p>



<p class="wp-block-paragraph">To create a new Revit add-in, open up Visual Studio and start a new Class Library project.</p>



<p class="wp-block-paragraph">Visual Studio is kind enough to provide us with a class, named “Class1.cs”.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/RevitAPITutorial_4.png" alt="The class that will hold our Revit external command"/></figure>



<p class="wp-block-paragraph">Either rename it, or delete it and replace it with another class (.cs) file, and make sure the new class is named something that makes sense. I’m naming mine “RevitTutorialExternalCommand”. Once that’s done, we’re going to make our new class implement the interface “IExternalCommand”.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/RevitAPITutorial_5.png" alt="Implementing the Revit IExternalCommand interface"/></figure>



<p class="wp-block-paragraph">As you probably know, that squiggly red underline means Visual Studio doesn&#8217;t recognize that reference. This is because IExternalCommand is an interface from the Revit API libraries. So to use it, we&#8217;ll have to add a reference in our project to the Revit API dlls. You can find these in the directory where you installed Revit. The files we&#8217;re looking for are RevitAPI.dll and RevitAPIUI.dll. These are the two libraries that you&#8217;ll use most often when developing add-ins for Revit.</p>



<p class="wp-block-paragraph">Once we&#8217;ve added references in our project to these files, we can add the line:</p>



<p class="wp-block-paragraph">using Autodesk.Revit.UI;</p>



<p class="wp-block-paragraph">to our class file.</p>



<p class="wp-block-paragraph">Now we still have the red squiggly underline; as you probably guessed, Visual Studio now recognizes the interface name, but it’s warning us that we’re not correctly implementing the interface. In order for our class to implement it, we have to add the Execute method to the class. This method has the following signature:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">C#</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>public Result Execute(
    ExternalCommandData commandData,
    ref string message,
    ElementSet elements)</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Result</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">Execute</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #4EC9B0">ExternalCommandData</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">commandData</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">ref</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">string</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">message</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #4EC9B0">ElementSet</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">elements</span><span style="color: #D4D4D4">)</span></span></code></pre></div>



<p class="wp-block-paragraph">The access modifier has to be public in order for Revit to be able to run our add-in. This method essentially serves as the entry point for your add-in – this is the equivalent of “public static void Main()”. There’s one more thing we should do before actually writing code – add an attribute that determines the transactional behavior of the external command. This attribute is in the namespace Autodesk.Revit.Attributes, so you’ll want to add that to your using statements. Revit transactions are outside the scope of this article, but the short version is that anything your add-in does to change the file that it’s working with has to be done within the scope of a transaction, so the TransactionMode enum that we supply to the Transaction attribute allows us to decide whether a transaction is automatically wrapped around our entire add-in, or whether we have to manually start and commit Transactions. It’s usually a good idea to use Manual, so that’s what I’m showing here.</p>



<p class="wp-block-paragraph">Finally, let’s write some code to make this add-in actually DO something. We’ll keep it simple for this first tutorial: we’ll just display a message box for the user.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/RevitAPITutorial_12.png" alt="Showing a TaskDialog in Revit API"/></figure>



<p class="wp-block-paragraph">In the above image, you can see I&#8217;ve used a class called TaskDialog&#8217;s &#8220;Show&#8221; method, and passed it two strings as its parameters. The first parameter is the &#8220;title&#8221; displayed at the top of the message box. The second parameter is the content text of the message box. At the end of our Execute method, we return an Autodesk.Revit.UI.Result, an enum with three possible values: &#8220;Cancelled&#8221;, &#8220;Succeeded&#8221;, and &#8220;Failed&#8221;. We&#8217;ll return Succeeded for now.</p>



<p class="wp-block-paragraph">Finally, we&#8217;ll build our solution, start Revit, and try it out.</p>



<p class="wp-block-paragraph">But wait, there&#8217;s a problem&#8230; When we have add-ins loaded, there&#8217;s supposed to be an &#8220;Add-ins&#8221; menu tab at the top, right next to &#8220;Modify&#8221;. You can see in the above picture that it&#8217;s not there. This is because we haven&#8217;t actually deployed our add-in so that it can be loaded by Revit. We need to do two things to make this happen:&nbsp;</p>



<ol class="wp-block-list">
<li>Write an add-in file (an XML file with a &#8220;.addin&#8221; extension) that Revit reads when it starts up in order to determine which add-ins are to be loaded</li>



<li>Build our project to produce a dll file, and place it somewhere accessible (we&#8217;ve already done this one)</li>
</ol>



<p class="wp-block-paragraph">Let&#8217;s go ahead and write that .addin file. You can do this using Notepad, Notepad++, or any other text editor. When creating the file, you need to put it in the add-ins folder for your targeted version of Revit, which can be found at C:\Users\[YOUR USERNAME]\AppData\Roaming\Autodesk\Revit\Addins\[YOUR REVIT VERSION YEAR]. So for me, it&#8217;s C:\Users\Christopher Olsen\AppData\Roaming\Autodesk\Revit\Addins\2014. The AppData folder is usually hidden by default, so you&#8217;ll have to make sure Windows Explorer is configured to show hidden files and folders.</p>



<p class="wp-block-paragraph">&nbsp;</p>



<p class="wp-block-paragraph">As mentioned before, this .addin file is in XML format.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/RevitAPITutorial_14.png" alt="A sample Revit .addin manifest file"/></figure>



<p class="wp-block-paragraph">Our root element here is the RevitAddIns tag. Within this tag, you&#8217;ll place one or more Addin tags (yes, you can use one file to specify multiple add-ins for Revit to load). The &#8220;Type&#8221; attribute on the Add-in tag is for specifying what kind of add-in this is. The two most popular options are &#8220;Command&#8221; and &#8220;Application&#8221;. Since we&#8217;ve written an external command (as indicated by the fact that we used the IExternalCommand interface), we&#8217;ll use the &#8220;Command&#8221; value for this attribute.</p>



<p class="wp-block-paragraph">&nbsp;</p>



<p class="wp-block-paragraph">Nested inside the AddIn tag, we have several important elements. The Text tag is where we specify the display name for our add-in in the &#8220;External Commands&#8221; drop-down menu in Revit. The Assembly tag must contain the file path to the dll for our add-in &#8211; in this example, I&#8217;ve pointed it toward the dll file in my project&#8217;s obj\Debug folder in order to make testing and debugging easier. AddInId is essentially the ID of your add-in, and must be unique for a session of Revit &#8211; the best way to do this is to generate a new GUID in visual studio (you can do this by going to the Tools menu, and clicking on &#8220;Create GUID&#8221;. You don&#8217;t have to put this GUID in your code somewhere, but it&#8217;s common practice to place it in a comment right above your class definition.</p>



<p class="wp-block-paragraph">Next, we have the FullClassName tag, which must contain the namespace and class name for your external command. The VendorID tag is required, and is supposed to be unique for a given session of Revit &#8211; Autodesk recommends using the url of your company&#8217;s website. Finally, VendorDescription is a more verbose description of your company &#8211; if your external command throws an unhandled exception, Revit will display an error message on screen that ends with &#8220;For more info, contact this knucklehead that developed the add-in: [VendorDescription]&#8221;. I&#8217;ve paraphrased the actual text of the error message, for comical effect.</p>



<p class="wp-block-paragraph">&nbsp;</p>



<p class="wp-block-paragraph">And that&#8217;s it. There are many more things we can specify in that .addin file, but these are the core ones you&#8217;ll really want to use. Other tags you can add to this file include the path to an image that will be displayed for your add-in in the external command drop-down menu. For a full run-down, check out the table on Autodesk&#8217;s <a href="https://www.revitapidocs.com/" target="_blank" rel="noreferrer noopener">knowledge base website</a>.</p>



<p class="wp-block-paragraph">&nbsp;</p>



<p class="wp-block-paragraph">Now, if we open Revit, we see that the &#8220;Add-Ins&#8221; tab has been added, and clicking on the &#8220;External Tools&#8221; drop-down shows us our add-in. If we click on it, our external command&#8217;s &#8220;Execute&#8221; method runs, and we get our message box.</p>



<p class="wp-block-paragraph">Now that we’ve got the super basic stuff out of the way, we can turn our attention to doing something meaningful in a Revit add-in. In my next blog post, we’ll go over how we can have our user select elements, and how we can then perform operations on those elements.</p>



<p class="wp-block-paragraph"><a href="https://static.dmcinfo.com/services/application-development/pc-application-development" target="_blank">Learn more about how DMC can help you develop custom software.</a></p>



<p class="wp-block-paragraph"></p>
<p>The post <a href="https://static.dmcinfo.com/blog/24963/the-revit-api-creating-your-first-add-in/">The Revit API: Creating Your First Add-In</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>6 Easy Steps to Get Started with MVC Module Development in DNN 8</title>
		<link>https://static.dmcinfo.com/blog/25071/6-easy-steps-to-get-started-with-mvc-module-development-in-dnn-8/</link>
		
		<dc:creator><![CDATA[DMC]]></dc:creator>
		<pubDate>Fri, 14 Oct 2016 12:37:43 +0000</pubDate>
				<category><![CDATA[Web Application Development]]></category>
		<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[C# .NET Application Development]]></category>
		<category><![CDATA[Dot Net Nuke]]></category>
		<category><![CDATA[HTML and CSS]]></category>
		<category><![CDATA[MS Visual Studio/.NET]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Web]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/25071/6-easy-steps-to-get-started-with-mvc-module-development-in-dnn-8/</guid>

					<description><![CDATA[<p>In the beginning of the year,&#160;DNN (formerly DotNetNuke) was updated to support MVC modules. MVC is the latest version of ASP.NET in which the Model-View-Controller paradigm is at the core.&#160;This article won&#8217;t be a look into what MVC is or a comparison with WebForms, but instead will give a quick guide into starting DNN MVC [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/25071/6-easy-steps-to-get-started-with-mvc-module-development-in-dnn-8/">6 Easy Steps to Get Started with MVC Module Development in DNN 8</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">In the beginning of the year,&nbsp;DNN (formerly DotNetNuke) was updated to support MVC modules. MVC is the latest version of ASP.NET in which the Model-View-Controller paradigm is at the core.&nbsp;This article won&#8217;t be a look into what MVC is or a comparison with WebForms, but instead will give a quick guide into starting DNN MVC module development.</p>



<p class="wp-block-paragraph">While there are some guides available that give you similar information, I found it a bit difficult to get started developing MVC modules in DNN. For reference, the articles I used are at the bottom of this blog.</p>



<p class="wp-block-paragraph">Here&#8217;s an overview of the steps we&#8217;ll take to get started.</p>



<ol class="wp-block-list">
<li><a href="#prerequisites">Prerequisites</a></li>



<li><a href="#templates">Templates</a></li>



<li><a href="#setup">Setup</a></li>



<li><a href="#build">Build</a></li>



<li><a href="#installation">Installation</a></li>



<li><a href="#next-steps">Next Steps</a></li>



<li><a href="#references">References</a></li>
</ol>



<h2 id="prerequisites" class="wp-block-heading">1. Prerequisites</h2>



<p class="wp-block-paragraph">For this quick start, you&#8217;ll need a few things before we can dive in.</p>



<p class="wp-block-paragraph">First, you&#8217;ll need to have Visual Studio 2015 installed. The express editions have been reported to be incompatible with the templates we&#8217;ll be using later, but this may not be true by the time you&#8217;re reading this.</p>



<p class="wp-block-paragraph">Next, you&#8217;ll need to have IIS (Internet Information Services) setup with a local installation of DNN (version 8 or higher). There are many tutorials on how to do this around the web. You&#8217;ll need to install IIS and&nbsp;Microsoft SQL Server, then you can install DNN by downloading the latest _install.zip from <a href="https://github.com/dnnsoftware/Dnn.Platform/releases" target="_blank">DNN&#8217;s GitHub releases</a>.</p>



<p class="wp-block-paragraph">Once those are all set up, you&#8217;re ready to go.</p>



<h2 id="templates" class="wp-block-heading">2. Templates</h2>



<p class="wp-block-paragraph">You <em>could&nbsp;</em>create a module from scratch. But why would you do that when a DNN expert created templates for you to use? <a href="https://marketplace.visualstudio.com/items?itemName=Chris-Hammond.DotNetNukeDNNDevelopmentProjectTemplates" target="_blank" rel="noreferrer noopener">Download the templates from the Visual Studio Gallery</a>&nbsp;and run through the installation procedure.</p>



<h2 id="setup" class="wp-block-heading">3. Setup</h2>



<p class="wp-block-paragraph">Now that everything is set up, we can actually dive into creating the module.&nbsp;</p>



<p class="wp-block-paragraph">In Visual Studio, select File -&gt; New -&gt; Project</p>



<p class="wp-block-paragraph">In the New Project window, select Templates -&gt; Visual C# -&gt; DotNetNuke and you&#8217;ll see a listing of the types of projects the templates have provided.</p>



<p class="wp-block-paragraph">To create an MVC module, we&#8217;ll select DotNetNuke 8 C# DAL2 MVC Module. There are three other fields we must configure: Name, Location, and Solution name.</p>



<p class="wp-block-paragraph"><strong>Name: </strong>Enter a name for your project (it&#8217;s best not to use any spaces or special characters for this)</p>



<p class="wp-block-paragraph"><strong>Location:&nbsp;</strong>This is important to point this to the correct folder in DNN: /DesktopModules/MVC/.&nbsp;Depending on your installation directory, the folder should be something like C:\Dev\Projects\DMC_Website\Alpha\DesktopModules\MVC\ where &#8220;Alpha&#8221; is the root of your DNN installation.</p>



<p class="wp-block-paragraph"><strong>Solution name:</strong>&nbsp;We&#8217;re not actually going to be using this field. Uncheck&nbsp;the box on the right that says &#8220;Create directory for solution&#8221; and the solution name textbox will be greyed out.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/2016-10-28-12_40_42-New-Project.png" alt="Configuration of the DotNetNuke 8 C# DAL2 MVC Module Visual Studio Project"/></figure>



<p class="wp-block-paragraph">Confirm your settings look similar to mine and then click OK.</p>



<p class="wp-block-paragraph">A Project Setup Wizard dialog box will appear asking for some project information. Many of these are self explanatory, so I will only address the two that are a bit tricky.</p>



<p class="wp-block-paragraph"><strong>Namespace: </strong>Whatever namespace you want your module to live in. The templates will automatically include your project name in the namespace, so no need to enter it here.&nbsp;Make sure you include the last period. E.g. DMC.</p>



<p class="wp-block-paragraph"><strong>Local Dev URL:&nbsp;</strong>By default this is set up to point to dnndev.me, which is actually set up to point back to 127.0.0.1 (your localhost). What you enter here depends on what settings you&#8217;ve set your DNN install up with. For my installation, I access my local DNN install through http://localhost./ Therefore, I am going to enter localhost as my Local Dev URL.</p>



<p class="wp-block-paragraph">Initial values</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/2016-10-14-12_49_25-Project-Setup-Wizard.png" alt="DNN Template Setup Wizard Initial Values"/></figure>



<p class="wp-block-paragraph">Updated values (note: the owner website field includes https:// but the textbox isn&#8217;t large enough to display it. Be sure to include it in your URL.)</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/2016-10-28-12_42_14-Project-Setup-Wizard.png" alt="DNN Template Setup Wizard Updated Values"/></figure>



<p class="wp-block-paragraph">Once all fields have been complete, click OK.</p>



<h2 id="build" class="wp-block-heading">4. Build</h2>



<p class="wp-block-paragraph">Now that the initial project setup is complete, you&#8217;ll be presented with a web page in Visual Studio that says * Important *. These are steps that you should&nbsp;<strong>read carefully</strong>&nbsp;and follow to ensure your project will work correctly. I&#8217;ll provide a quick overview of these steps in case the original wording is confusing for anyone.</p>



<p class="wp-block-paragraph">First, check IIS to see if any of your folders were converted to virtual directories or applications. To do this, open IIS, expand your site&#8217;s dropdown and check what icon is displayed next to your DesktopModules folder or the MVC folder inside of the DesktopModules folder. If it&#8217;s anything other than a yellow folder, right click it and click remove.</p>



<p class="wp-block-paragraph">Next, in Visual Studio, right click and delete the web.config files that are in the solution.</p>



<p class="wp-block-paragraph">You can now build the module! change the solution configuration dropdown from Debug to Release and then select Build -&gt; Build</p>



<p class="wp-block-paragraph">You&#8217;ll get an install .zip file in your module&#8217;s install/ directory.</p>



<h2 id="installation" class="wp-block-heading">5. Installation</h2>



<p class="wp-block-paragraph">Now, in DNN, go to Hosts -&gt; Extensions and click Install Extension, selecting your install .zip file that you previously built.</p>



<p class="wp-block-paragraph">If everything goes well, then the module is now installed and can be placed on any page.</p>



<h2 id="next-steps" class="wp-block-heading">6. Next Steps</h2>



<p class="wp-block-paragraph">Once you&#8217;ve dragged the module into a page, you&#8217;ll see a demo application that includes multiple views, database interaction, and more. Simply build the project in debug mode to automatically copy the new DLL to the /bin folder.</p>



<h2 id="references" class="wp-block-heading">7. References</h2>



<ul class="wp-block-list">
<li><a href="https://www.chrishammond.com/tag/dotnetnuke" type="link" id="https://www.chrishammond.com/tag/dotnetnuke" target="_blank" rel="noreferrer noopener">Chris Hammond&#8217;s DNN posts</a></li>



<li><a href="https://dnncommunity.org/blogs" type="link" id="https://dnncommunity.org/blogs" target="_blank" rel="noreferrer noopener">DNN Community Blogs</a></li>



<li><a href="https://www.dnnsoftware.com/docs/developers/mvc-modules/mvc-module-development.html" type="link" id="https://www.dnnsoftware.com/docs/developers/mvc-modules/mvc-module-development.html" target="_blank" rel="noreferrer noopener">DNN MVC Module Development</a></li>
</ul>



<p class="wp-block-paragraph">While you&#8217;re here, check out DMC&#8217;s <a href="/services/application-development/web-application-development">Web Application Development</a> and <a href="/services/application-development/web-application-development/aspnet-and-aspnet-mvc">ASP.NET &amp; ASP.NET MVC Development</a> services so we can get started on your next DNN MVC module!</p>



<p class="wp-block-paragraph"></p>
<p>The post <a href="https://static.dmcinfo.com/blog/25071/6-easy-steps-to-get-started-with-mvc-module-development-in-dnn-8/">6 Easy Steps to Get Started with MVC Module Development in DNN 8</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
