<?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>Web Archives | DMC, Inc.</title>
	<atom:link href="https://static.dmcinfo.com/blog/tag/web/feed/index.xml" rel="self" type="application/rss+xml" />
	<link></link>
	<description></description>
	<lastBuildDate>Mon, 27 Jul 2026 21:16:57 +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>Web 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>DMC Achieves Microsoft’s Gold Cloud Productivity Competency</title>
		<link>https://static.dmcinfo.com/blog/24370/dmc-achieves-microsofts-gold-cloud-productivity-competency/</link>
		
		<dc:creator><![CDATA[DMC]]></dc:creator>
		<pubDate>Mon, 08 May 2017 10:17:31 +0000</pubDate>
				<category><![CDATA[Announcements]]></category>
		<category><![CDATA[Azure]]></category>
		<category><![CDATA[Business Intelligence]]></category>
		<category><![CDATA[Digital Workplace Solutions]]></category>
		<category><![CDATA[IoT]]></category>
		<category><![CDATA[Office 365]]></category>
		<category><![CDATA[SharePoint]]></category>
		<category><![CDATA[Web Application Development]]></category>
		<category><![CDATA[Office 365 BI]]></category>
		<category><![CDATA[Office 365 Migration]]></category>
		<category><![CDATA[Power BI]]></category>
		<category><![CDATA[Server Assessment]]></category>
		<category><![CDATA[SharePoint BI]]></category>
		<category><![CDATA[SQL Server BI]]></category>
		<category><![CDATA[Web]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/24370/dmc-achieves-microsofts-gold-cloud-productivity-competency/</guid>

					<description><![CDATA[<p>DMC recently upgraded our Silver Cloud Productivity competency&#160;to Microsoft Gold for&#160;Cloud Productivity! This certification recognizes DMC for its expertise and experience helping clients deploy Microsoft cloud and hybrid solutions.&#160;Hybrid solutions&#160;rely on a combination of cloud and&#160;existing investments in&#160;on-premises resources.&#160; This Microsoft Gold level certification makes DMC&#160;eligible for exclusive training opportunities that further the implementation expertise [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/24370/dmc-achieves-microsofts-gold-cloud-productivity-competency/">DMC Achieves Microsoft’s Gold Cloud Productivity Competency</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p class="wp-block-paragraph">DMC recently upgraded our Silver Cloud Productivity competency&nbsp;to <strong>Microsoft Gold for&nbsp;Cloud Productivity</strong>! This certification recognizes DMC for its expertise and experience helping clients deploy Microsoft cloud and hybrid solutions.&nbsp;Hybrid solutions&nbsp;rely on a combination of cloud and&nbsp;existing investments in&nbsp;on-premises resources.&nbsp;</p>

<p class="wp-block-paragraph">This Microsoft Gold level certification makes DMC&nbsp;eligible for exclusive training opportunities that further the implementation expertise we provide to our Clients. DMC also obtains access to exclusive support from Microsoft engineers, allowing us to provide world-class support services to our Clients.</p>

<h2 class="wp-block-heading">What is the Microsoft Cloud?&nbsp;</h2>

<p class="wp-block-paragraph">The <a href="https://cloud.microsoft.com/en-us/?SEMID=1&amp;WT_srch=1&amp;ocid=CLD_SEM_Google_BRAND_CON_en-US_%20microsoft%20%20cloud&amp;wt_mc_id=CLD_SEM_Google_BRAND_CON_en-US_%20microsoft%20%20cloud" target="_blank">Microsoft Cloud</a> is a secure platform that includes:</p>

<ul class="wp-block-list">
 <li>Pre-built solutions (e.g. <a href="https://static.dmcinfo.com/services/digital-workplace-solutions/microsoft-consulting-services/office-365">Office 365</a> Exchange, <a href="https://static.dmcinfo.com/services/digital-workplace-solutions/microsoft-consulting-services/sharepoint">SharePoint</a>, Skype for Business, <a href="https://static.dmcinfo.com/services/application-development/iot-solutions">Azure IoT</a>, <a href="https://static.dmcinfo.com/services/digital-workplace-solutions/microsoft-consulting-services/business-intelligence">Power BI</a>, etc.),</li>
 <li>Infrastructure (e.g. <a href="https://static.dmcinfo.com/services/digital-workplace-solutions/microsoft-consulting-services/microsoft-azure-cloud-solutions-and-services">Azure</a> virtual machines, storage, etc.)</li>
 <li>Services (e.g. <a href="https://static.dmcinfo.com/services/digital-workplace-solutions/microsoft-consulting-services/microsoft-azure-cloud-solutions-and-services">Azure</a> web apps, mobile apps, <a href="https://static.dmcinfo.com/services/digital-workplace-solutions/microsoft-consulting-services/business-intelligence">SQL</a> database, machine learning, etc.)</li>
</ul>

<p class="wp-block-paragraph">These offerings can be assembled to provide a scalable and complete collaboration suite with the potential to&nbsp;transform the way teams work. With the cloud, high-performance computing and agility help businesses expand their growth quickly.</p>

<h2 class="wp-block-heading">What does it take to&nbsp;become Gold Cloud Productivity Certified?</h2>

<p class="wp-block-paragraph">To become a Microsoft Gold Cloud Productivity certified partner, DMC had to provide evidence of its expertise in this area, which includes&nbsp;deploying a minimum of&nbsp;4,000 users of Exchange Online, SharePoint Online, Skype for Business, Yammer, and Office ProPlus.&nbsp;</p>

<p class="wp-block-paragraph">Additionally, two DMC engineers passed&nbsp;rigorous Microsoft cloud and hybrid implementation exams focused on managing identities &amp; authentication, as well as deploying Office 365 services.&nbsp;<br />
<br />
Finally, DMC had to provide references from a minimum of&nbsp;five customers&nbsp;within the previous 12 months from customers whom we provided solutions based on the products and technologies associated with Cloud Productivity.</p>

<h2 class="wp-block-heading">DMC Cloud Services</h2>

<p class="wp-block-paragraph">Check out DMC&apos;s <a href="https://static.dmcinfo.com/services/digital-workplace-solutions/microsoft-consulting-services/microsoft-azure-cloud-solutions-and-services" target="_blank">Microsoft Azure Cloud Solutions and Services</a>&nbsp;and our&nbsp;<a href="https://static.dmcinfo.com/services/digital-workplace-solutions/microsoft-consulting-services/office-365" target="_blank">Office 365 Cloud</a>&nbsp;services. You can <a href="https://static.dmcinfo.com/contact.aspx" target="_blank">contact DMC</a> if you have questions or need help getting your Cloud Productivity initiative up and running.&nbsp;<br />
<br />
<strong><a href="/services/digital-workplace-solutions/microsoft-consulting-services" target="_blank">Learn more about DMC&apos;s Microsoft consulting services.</a></strong></p>
<p>The post <a href="https://static.dmcinfo.com/blog/24370/dmc-achieves-microsofts-gold-cloud-productivity-competency/">DMC Achieves Microsoft’s Gold Cloud Productivity Competency</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>Easy XML Parsing in C#/.NET With the HTML Agility Pack</title>
		<link>https://static.dmcinfo.com/blog/24980/easy-xml-parsing-in-c-net-with-the-html-agility-pack/</link>
		
		<dc:creator><![CDATA[DMC]]></dc:creator>
		<pubDate>Mon, 31 Oct 2016 16:57:45 +0000</pubDate>
				<category><![CDATA[Web Application Development]]></category>
		<category><![CDATA[C# .NET Application Development]]></category>
		<category><![CDATA[SDK, API, and Driver]]></category>
		<category><![CDATA[Web]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/24980/easy-xml-parsing-in-c-net-with-the-html-agility-pack/</guid>

					<description><![CDATA[<p>In 2006, the newspaper USA Today&#160;included the Internet in its list of the &#8220;New Seven Wonders of the World.&#8221; The Internet has democratized access to vast stores of information in an unprecedented way&#160;and has transformed many aspects of education, industry, and society. This glut of information can give tremendous insight into everything from trends in [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/24980/easy-xml-parsing-in-c-net-with-the-html-agility-pack/">Easy XML Parsing in C#/.NET With the HTML Agility Pack</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">In 2006, the newspaper <em>USA Today</em>&nbsp;included the Internet in its list of the &#8220;New Seven Wonders of the World.&#8221; The Internet has democratized access to vast stores of information in an unprecedented way&nbsp;and has transformed many aspects of education, industry, and society. This glut of information can give tremendous insight into everything from trends in the price of chop sticks&nbsp;to predicting regional flu outbreaks across the globe &#8211; if you know how to efficiently access it.&nbsp;</p>



<p class="wp-block-paragraph">I recently started a personal project to monitor the real estate market in Houston to gain insight into trends in pricing, neighborhood composition, construction, etc. One vital piece of the puzzle was reliably and efficiently gathering detailed information on specific properties to monitor over time. Using <a href="http://www.zillow.com/howto/api/APIOverview.htm">Zillow.com&#8217;s Developer APIs</a> and the <a href="https://html-agility-pack.net/">HTML Agility Pack</a>, I was able to spin up a prototype over coffee one Sunday morning, and I wanted to share my experience using this powerful C# library.</p>



<h2 id="h-the-zillow-api" class="wp-block-heading">The Zillow API</h2>



<p class="wp-block-paragraph">The majority of modern websites use JSON as the data exchange format, as it is easily consumed by the widely-used JavaScript language, but there are a significant number of sites (including Zillow.com) that use XML as the exchange format. There are advantages and disadvantages to each, but both formats are straightforward to parse and are human-readable.&nbsp;</p>



<p class="wp-block-paragraph">Zillow provides several useful APIs, and I chose <a href="https://www.bridgeinteractive.com/developers/zillow-group-data/" type="link" id="https://www.bridgeinteractive.com/developers/zillow-group-data/" target="_blank" rel="noreferrer noopener">GetDeepSearchResults</a> because it encapsulates most of the data I want to track in my application. The documentation is refreshingly complete and useful: you can see details about each field, the XML schema, error codes, and an example usage. After obtaining my developer API key, I scratched out a few lines of code to load the results.</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">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> private void LoadResults(string property)
 {
     // Argument "property" is a URL-encoded string containing a single property address, city, and state
     string addr = "http://www.zillow.com/webservice/GetDeepSearchResults.htm";
     string key = "?&#91;My_API_Key&#93;&amp;";
     string results = String.Empty;

     // Create a new HTTP client to communicate with the Zillow server
     HttpClient client = new HttpClient();
     client.BaseAddress = new Uri(addr);

     // Load the results of the querty
     HttpResponseMessage response = client.GetAsync(key + property).Result;
     if (response.IsSuccessStatusCode)
     {
         results = response.Content.ReadAsStringAsync();
     }
     else
     {
         Debug.WriteLine("Web call failed with code " + response.StatusCode);
     }
     return results;
 }</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: #569CD6">private</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">void</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">LoadResults</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">string</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">property</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #6A9955">     // Argument &quot;property&quot; is a URL-encoded string containing a single property address, city, and state</span></span>
<span class="line"><span style="color: #D4D4D4">     </span><span style="color: #569CD6">string</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">addr</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;http://www.zillow.com/webservice/GetDeepSearchResults.htm&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">     </span><span style="color: #569CD6">string</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">key</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;?&#91;My_API_Key&#93;&amp;&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">     </span><span style="color: #569CD6">string</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">results</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">String</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Empty</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">     // Create a new HTTP client to communicate with the Zillow server</span></span>
<span class="line"><span style="color: #D4D4D4">     </span><span style="color: #4EC9B0">HttpClient</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">client</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">HttpClient</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">     </span><span style="color: #9CDCFE">client</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">BaseAddress</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Uri</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">addr</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">     // Load the results of the querty</span></span>
<span class="line"><span style="color: #D4D4D4">     </span><span style="color: #4EC9B0">HttpResponseMessage</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">response</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">client</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">GetAsync</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">key</span><span style="color: #D4D4D4"> + </span><span style="color: #9CDCFE">property</span><span style="color: #D4D4D4">).</span><span style="color: #9CDCFE">Result</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">response</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">IsSuccessStatusCode</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: #9CDCFE">results</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">response</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Content</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">ReadAsStringAsync</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">else</span></span>
<span class="line"><span style="color: #D4D4D4">     {</span></span>
<span class="line"><span style="color: #D4D4D4">         </span><span style="color: #9CDCFE">Debug</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">WriteLine</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;Web call failed with code &quot;</span><span style="color: #D4D4D4"> + </span><span style="color: #9CDCFE">response</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">StatusCode</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">return</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">results</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4"> }</span></span></code></pre></div>



<p class="wp-block-paragraph">The LoadResults function takes in a well-formed URL-encoded property listing string that meets the requirements listed in the API documentation, and returns either an empty string (if the API call failed) or an XML-encoded string containing the property details.</p>



<h2 id="h-parsing-with-agility" class="wp-block-heading">Parsing with Agility</h2>



<p class="wp-block-paragraph">I could have spent some time brewing up a <a href="https://msdn.microsoft.com/en-us/library/az24scfc(v=vs.110).aspx">RegEx</a>-powered parser for the XML results &#8211;&nbsp;after all, this is a well-documented API, and I know what to expect from each call. But why re-invent the wheel? It&#8217;s also worth pointing out that not all APIs (or web pages, which you can also easily scrape with the HTML Agility Pack) are as consistent and well-formed, so your homebrewed parser might work for a while until it tries to handle a malformed response.&nbsp;</p>



<p class="wp-block-paragraph">Using the Agility Pack and the Zillow documentation, I can easily parse out the XML tags I care about without writing a single regex.</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">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> private PropertyData ParseResults(string results)
 {
     // Create an instance of the PropertyData to store the results
     PropertyData data = new PropertyData();

     // Load the API result string
     HtmlDocument doc = new HtmlDocument();
     doc.LoadHtml(results);

     // Find the parameters that will be tracked
     var zpid = doc.DocumentNode.Descendants("zpid").FirstOrDefault().InnerText;
     var finSize = doc.DocumentNode.Descendants("finishedSqFt").FirstOrDefault().InnerText;
     var zestValue = doc.DocumentNode.Descendants("amount").FirstOrDefault().InnerText;
     var baths = doc.DocumentNode.Descendants("bathrooms").FirstOrDefault().InnerText;
     var beds = doc.DocumentNode.Descendants("bedrooms").FirstOrDefault().InnerText;

     // Parse these value strings into their expected data types
     data.Zpid = int.Parse(zpid);
     data.FinishedSize = int.Parse(finSize);
     data.ZestValue = double.Parse(zestValue);
     data.Bathrooms = double.Parse(baths);
     data.Bedrooms = double.Parse(beds);

     return data;
 }</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: #569CD6">private</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">PropertyData</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">ParseResults</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">string</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">results</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #6A9955">     // Create an instance of the PropertyData to store the results</span></span>
<span class="line"><span style="color: #D4D4D4">     </span><span style="color: #4EC9B0">PropertyData</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">PropertyData</span><span style="color: #D4D4D4">();</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">     // Load the API result string</span></span>
<span class="line"><span style="color: #D4D4D4">     </span><span style="color: #4EC9B0">HtmlDocument</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">doc</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">HtmlDocument</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">     </span><span style="color: #9CDCFE">doc</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">LoadHtml</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">results</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">     // Find the parameters that will be tracked</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">zpid</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">doc</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">DocumentNode</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">Descendants</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;zpid&quot;</span><span style="color: #D4D4D4">).</span><span style="color: #DCDCAA">FirstOrDefault</span><span style="color: #D4D4D4">().</span><span style="color: #9CDCFE">InnerText</span><span style="color: #D4D4D4">;</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">finSize</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">doc</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">DocumentNode</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">Descendants</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;finishedSqFt&quot;</span><span style="color: #D4D4D4">).</span><span style="color: #DCDCAA">FirstOrDefault</span><span style="color: #D4D4D4">().</span><span style="color: #9CDCFE">InnerText</span><span style="color: #D4D4D4">;</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">zestValue</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">doc</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">DocumentNode</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">Descendants</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;amount&quot;</span><span style="color: #D4D4D4">).</span><span style="color: #DCDCAA">FirstOrDefault</span><span style="color: #D4D4D4">().</span><span style="color: #9CDCFE">InnerText</span><span style="color: #D4D4D4">;</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">baths</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">doc</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">DocumentNode</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">Descendants</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;bathrooms&quot;</span><span style="color: #D4D4D4">).</span><span style="color: #DCDCAA">FirstOrDefault</span><span style="color: #D4D4D4">().</span><span style="color: #9CDCFE">InnerText</span><span style="color: #D4D4D4">;</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">beds</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">doc</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">DocumentNode</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">Descendants</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;bedrooms&quot;</span><span style="color: #D4D4D4">).</span><span style="color: #DCDCAA">FirstOrDefault</span><span style="color: #D4D4D4">().</span><span style="color: #9CDCFE">InnerText</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">     // Parse these value strings into their expected data types</span></span>
<span class="line"><span style="color: #D4D4D4">     </span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Zpid</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">int</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">Parse</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">zpid</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">     </span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">FinishedSize</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">int</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">Parse</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">finSize</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">     </span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">ZestValue</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">double</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">Parse</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">zestValue</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">     </span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Bathrooms</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">double</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">Parse</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">baths</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">     </span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Bedrooms</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">double</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">Parse</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">beds</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">     </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4"> }</span></span></code></pre></div>



<p class="wp-block-paragraph">That&#8217;s all there is to it! No bulky regular expressions or clunky homebrewed parsing code. For clarity, I stripped out a lot of input sanitation and error handling code, so don&#8217;t forget to check for exception conditions!</p>



<h2 id="h-other-applications" class="wp-block-heading">Other Applications</h2>



<p class="wp-block-paragraph">You may have an inkling that a parsing tool like the HTML Agility Pack can work for more than just parsing XML responses. You would be correct. Another key area where this library can come into play is data scraping (or web data extraction). If an API is not available or doesn&#8217;t give you all of the information you need, you can load the web page and parse the whole thing for the data you need.&nbsp;</p>



<p class="wp-block-paragraph">It&#8217;s very important to note that web scraping may violate the Terms of Use for a site, and if your scraping tool misbehaves and loads the webpage at a high rate, you run the risk of compromising the site&#8217;s resources and awaking the angry IT department kraken! Please be considerate, review the <a href="https://www.bloombergindustry.com/" type="link" id="https://www.bloombergindustry.com/">legality</a> of your application, and scrape responsibly!</p>



<p class="wp-block-paragraph">If you&#8217;ve used the HTML Agility Pack in an application or have questions about how I used it in mine, leave a comment below! Happy coding.</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 web application development.</a></strong></p>
<p>The post <a href="https://static.dmcinfo.com/blog/24980/easy-xml-parsing-in-c-net-with-the-html-agility-pack/">Easy XML Parsing in C#/.NET With the HTML Agility Pack</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>
		<item>
		<title>Automating Web Development &#8211; Tools</title>
		<link>https://static.dmcinfo.com/blog/26709/automating-web-development-tools/</link>
		
		<dc:creator><![CDATA[DMC]]></dc:creator>
		<pubDate>Tue, 07 Apr 2015 12:27:34 +0000</pubDate>
				<category><![CDATA[Web Application Development]]></category>
		<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[Dot Net Nuke]]></category>
		<category><![CDATA[HTML and CSS]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Web]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/26709/automating-web-development-tools/</guid>

					<description><![CDATA[<p>I’ve been working on a new DNN skin for a while now and much progress is being made. Along the way, I’ve learned about tools that can help speed up website development drastically. In this blog post, I’ll give an overview of these tools and how to use them by themselves and together to harness [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/26709/automating-web-development-tools/">Automating Web Development &#8211; Tools</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">I’ve been working on a new DNN skin for a while now and much progress is being made. Along the way, I’ve learned about tools that can help speed up website development drastically. In this blog post, I’ll give an overview of these tools and how to use them by themselves and together to harness the power of automation and simplify development tasks.</p>



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



<ul class="wp-block-list">
<li><a href="#ruby">Ruby</a></li>



<li><a href="#sass-or-less">Sass (or Less)</a></li>



<li><a href="#nodejs">Node.js</a></li>



<li><a href="#npm">npm</a></li>



<li><a href="#bower">Bower</a></li>



<li><a href="#grunt-or-gulp">Grunt or gulp</a></li>
</ul>



<h3 id="ruby" class="wp-block-heading">Ruby</h3>



<p class="wp-block-paragraph">We won’t be using Ruby as a programming language, but we will be needing it to install SASS.</p>



<p class="wp-block-paragraph">If you’re on Windows, download the <a href="https://rubyinstaller.org/" type="link" id="https://rubyinstaller.org/" target="_blank" rel="noreferrer noopener">latest version of Ruby</a></p>



<p class="wp-block-paragraph">If you’re on Linux or OS X, there are <a href="https://rvm.io/rvm/install" type="link" id="https://rvm.io/rvm/install" target="_blank" rel="noreferrer noopener">instructions you can follow</a></p>



<p class="wp-block-paragraph">Or, after installing cURL, run this in a terminal window:</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">Bash</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>\curl -sSL https://get.rvm.io/ | bash</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">\curl</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">-sSL</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">https://get.rvm.io/</span><span style="color: #D4D4D4"> | </span><span style="color: #DCDCAA">bash</span></span></code></pre></div>



<p class="wp-block-paragraph">Once Ruby has finished installing, no matter what platform you’re on, open a terminal window and run</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">Bash</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>ruby -v</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">ruby</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">-v</span></span></code></pre></div>



<p class="wp-block-paragraph">to ensure it has installed properly.</p>



<h3 id="sass-or-less" class="wp-block-heading">Sass (Syntactically Awesome Style Sheets) or Less</h3>



<p class="wp-block-paragraph">Sass is basically CSS with a ton of awesome features layered on top. Using Sass, which compiles to clean and efficient CSS, one can make use of extended abilities like variables, mixing, inline imports, and more.</p>



<p class="wp-block-paragraph">There is another CSS extension called Less, which is an alternative to Sass. I prefer Sass, but you could definitely adapt this tutorial to work with Less as well.</p>



<p class="wp-block-paragraph">Anyhow, now that Ruby is installed and ready to go, installing Sass is easy.</p>



<p class="wp-block-paragraph">In a terminal window, type</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">Bash</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>gem install sass</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">gem</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">install</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">sass</span></span></code></pre></div>



<p class="wp-block-paragraph">Once that is finished, run</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">Bash</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>sass -v</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">sass</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">-v</span></span></code></pre></div>



<p class="wp-block-paragraph">to ensure it has installed properly.</p>



<h3 id="nodejs" class="wp-block-heading">Node.js</h3>



<p class="wp-block-paragraph">Node.js is tool that allows one to write simple JavaScript programs that create powerful applications.</p>



<p class="wp-block-paragraph">We’ll be using Node.js to power npm (node package manager), Bower, and Grunt.</p>



<p class="wp-block-paragraph"><a href="https://nodejs.org/download/" type="link" id="https://nodejs.org/download/" target="_blank" rel="noreferrer noopener">Grab the proper download for your platform</a></p>



<p class="wp-block-paragraph">To install Node.js on Windows or OS X, simply run the installers.</p>



<p class="wp-block-paragraph">On Linux, you can build Node.js by using these steps:</p>



<p class="wp-block-paragraph">Extract the downloaded archive and open a terminal window</p>



<p class="wp-block-paragraph">1. Navigate to where you extracted the archive</p>



<p class="wp-block-paragraph">2. Run</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>./configure</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">configure</span></span></code></pre></div>



<p class="wp-block-paragraph">3. Run and wait patiently</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>make</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: #9CDCFE">make</span></span></code></pre></div>



<p class="wp-block-paragraph">4. Run</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>sudo make install</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: #9CDCFE">sudo</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">make</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">install</span></span></code></pre></div>



<p class="wp-block-paragraph">And you’ll be all set with Node.js.</p>



<h3 id="npm" class="wp-block-heading">npm</h3>



<p class="wp-block-paragraph">npm is the official package manager for Node.js. What this means is that using npm, one can install hundreds of different applications and tools that are built with Node.js.</p>



<p class="wp-block-paragraph">We’ll be using npm to install Bower and Grunt.</p>



<p class="wp-block-paragraph">npm comes installed with Node.js, so there are no additional steps required to install it.</p>



<h3 id="bower" class="wp-block-heading">Bower</h3>



<p class="wp-block-paragraph">Bower, much like npm, is a package manager. However, npm only deals with Node.js packages while Bower titles itself “a package manager for the web.” Using Bower, one can run a simple terminal command to download and install many different web libraries or frameworks, such as jQuery, Bootstrap, FontAwesome, and more.</p>



<p class="wp-block-paragraph">To install Bower, open a terminal window and type:</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>npm install -g bower</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: #9CDCFE">npm</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">install</span><span style="color: #D4D4D4"> -</span><span style="color: #9CDCFE">g</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">bower</span></span></code></pre></div>



<p class="wp-block-paragraph">(The -g flag is to install bower globally, so we can call it from the command line anywhere)</p>



<h3 id="grunt-or-gulp" class="wp-block-heading">Grunt or gulp</h3>



<p class="wp-block-paragraph">Grunt is a task runner that performs the time-consuming, repetitive tasks that come along with website development like minification, SASS compilation, and more.&nbsp;</p>



<p class="wp-block-paragraph">Thanks to npm, Grunt is just as easy to install as Bower:</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>npm install -g grunt-cli</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: #9CDCFE">npm</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">install</span><span style="color: #D4D4D4"> -</span><span style="color: #9CDCFE">g</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">grunt</span><span style="color: #D4D4D4">-</span><span style="color: #9CDCFE">cli</span></span></code></pre></div>



<p class="wp-block-paragraph">gulp (don’t you ever capitalize that g) is a similar tool that <em>should</em> provide better performance than Grunt because it uses Node.js’s streams.</p>



<p class="wp-block-paragraph">npm comes in handy once again. Install gulp with:</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>npm install -g gulp</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: #9CDCFE">npm</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">install</span><span style="color: #D4D4D4"> -</span><span style="color: #9CDCFE">g</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">gulp</span></span></code></pre></div>



<h2 id="h-beginning-automation" class="wp-block-heading">Beginning Automation</h2>



<p class="wp-block-paragraph">Now that we have all of the tools we need to begin, we can finally start creating an automated build system.</p>



<p class="wp-block-paragraph">There are tasks associated with web development that quickly become repetitive and mundane. Thankfully, we will no longer have to do these manually!</p>



<p class="wp-block-paragraph">The tasks that we can now automate are (in no particular order):</p>



<ul class="wp-block-list">
<li>Sass (or Less) compilation (converting our Sass or Less to standard CSS)</li>



<li>Concatenation (combining multiple files into one)</li>



<li>Minification (smushing text together to reduce the size, making it load faster)</li>



<li>Linting (automatically checking code for errors)</li>



<li>Copying of files (like fonts)</li>



<li>Adding vendor-specific prefixes to our CSS (ensuring compatibility across browsers)</li>



<li>Detecting features that we require a user’s browser to have</li>



<li>More that I can’t think of!</li>
</ul>



<p class="wp-block-paragraph">And best of all, the build system will be smart enough to understand when a particular file changes to prevent rebuilding the entire thing.</p>



<p class="wp-block-paragraph">Stay tuned for the next article! For now, you can always take a look at DMC&#8217;s <a href="/services/application-development/web-application-development">Web Application Development</a> services, where we can harness the technologies outlined above for your needs.</p>



<p class="wp-block-paragraph"></p>
<p>The post <a href="https://static.dmcinfo.com/blog/26709/automating-web-development-tools/">Automating Web Development &#8211; Tools</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>RESTful Logins</title>
		<link>https://static.dmcinfo.com/blog/26935/restful-logins/</link>
		
		<dc:creator><![CDATA[DMC]]></dc:creator>
		<pubDate>Tue, 27 Jan 2015 15:16:31 +0000</pubDate>
				<category><![CDATA[Digital Workplace Solutions]]></category>
		<category><![CDATA[Web Application Development]]></category>
		<category><![CDATA[Web]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/26935/restful-logins/</guid>

					<description><![CDATA[<p>If you are constructing a web application, you will probably have to create a login page that generates a user session. If you are not aware, RESTful (representational state transfer) URLs are considered best practice for internet applications. As a general rule (only to be broken under duress), RESTful URLs should be nouns, while the [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/26935/restful-logins/">RESTful Logins</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p class="wp-block-paragraph">If you are constructing a web application, you will probably have to create a login page that generates a user session. If you are not aware, RESTful (representational state transfer) URLs are considered best practice for internet applications. As a general rule (only to be broken under duress), RESTful URLs should be nouns, while the HTTP method is the verb. For example, if you want to see a user profile page and the user ID is 8, then a RESTful URL would be https://host/users/8/. &ldquo;users&rdquo; is a noun, and the HTTP method you would use is GET. An outdated, RPC-like (remote procedure call) URL might be https://host/GetUser/?id=8. &ldquo;GetUser&rdquo; is a sentence and not a noun, and so is not a resource and should not be referred to by a URL (uniform resource locator).</p>

<p class="wp-block-paragraph">So how do you resist the temptation to make a URL like https://host/login/, since &ldquo;login&rdquo; a verb and not a noun?</p>

<p class="wp-block-paragraph">Consider what is happening when you login to a web application. What resource is being accessed, created, or modified?</p>

<p class="wp-block-paragraph"><em>The session!</em></p>

<p class="wp-block-paragraph">So when making a login page, use URLs and HTTP methods as follows:</p>

<ul class="wp-block-list">
 <li>GET https://host/session/ retrieves a l<span style="line-height: 20.7999992370605px;">ogin page with a username and password form</span></li>
 <li>POST https://host/session/ submits your credentials</li>
 <li>DELETE https://host/session/ logs you out</li>
</ul>

<p class="wp-block-paragraph">DELETE is not available via HTML forms, so you&rsquo;ll have to use AJAX.</p>

<p class="wp-block-paragraph">One last note: why use POST to create the session rather than PUT, such as PUT https://host/session/username/?</p>

<p class="wp-block-paragraph">There are two reasons:</p>

<ol class="wp-block-list">
 <li>Your username will be unencrypted when querying a DNS for the IP address of the server.</li>
 <li>PUT is idempotent, so if you log in from separate clients, the first session will be semantically overwritten, logging you out. This doesn&apos;t usually actually happen since the session is stored in a token on the client side, but relying on this fact is an abuse of HTTP semantics.</li>
</ol>

<p class="wp-block-paragraph"><a href="/services/application-development/web-application-development">Learn more about DMC&apos;s web application development services.</a></p>
<p>The post <a href="https://static.dmcinfo.com/blog/26935/restful-logins/">RESTful Logins</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
