emGee Software Solutions Custom Database Applications

Share this

Tuts+ Code - Web Development

Updated: 43 min 52 sec ago

A Beginner's Guide to Regular Expressions in JavaScript

13 hours 34 min ago

Everyone working with JavaScript will have to deal with strings at one point or other. Sometimes, you will just have to store a string inside another variable and then pass it over. Other times, you will have to inspect it and see if it contains a particular substring.

However, things are not always this easy. There will be times when you will not be looking for a particular substring but a set of substrings which follow a certain pattern.

Let's say you have to replace all occurrences of "Apples" in a string with "apples". You could simply use theMainString.replace("Apples", "apples"). Nice and easy.

Now let's say you have to replace "appLes" with "apples" as well. Similarly, "appLES" should become "apples" too. Basically, all case variations of "Apple" need to be changed to "apple". Passing simple strings as an argument will no longer be practical or efficient in such cases.

This is where regular expressions come in—you could simply use the case-insensitive flag i and be done with it. With the flag in place, it doesn't matter if the original string contained "Apples", "APPles", "ApPlEs", or "Apples". Every instance of the word will be replaced with "apples".

Just like the case-insensitive flag, regular expressions offer a lot of other features which will be covered in this tutorial.

Using Regular Expressions in JavaScript

You have to use a slightly different syntax to indicate a regular expression inside different String methods. Unlike a simple string, which is enclosed in quotes, a regular expression consists of a pattern enclosed between slashes. Any flags that you use in a regular expression will be appended after the second slash.

Going back to the previous example, here is what the replace() method would look like with a regular expression and a simple string.

"I ate Apples".replace("Apples", "apples"); // I ate apples "I ate Apples".replace(/Apples/i, "apples"); // I ate apples "I ate aPPles".replace("Apples", "apples"); // I ate aPPles "I ate aPPles".replace(/Apples/i, "apples"); // I ate apples

As you can see, the regular expression worked in both cases. We will now learn more about flags and special characters that make up the pattern inside a regular expression.

Backslash in Regular Expressions

You can turn normal characters into special characters by adding a backslash before them. Similarly, you can turn special characters into normal characters by adding a backslash before them.

For example, d is not a special character. However, \d is used to match a digit character in a string. Similarly, D is not a special character either, but \D is used to match non-digit characters in a string.

Digit characters include 0, 1, 2, 3, 4, 5, 6, 7, 8, and 9. When you use \d inside a regular expression, it will match any of these nine characters. When you use \D inside a regular expression, it will match all the non-digit characters.

The following example should make things clear.

"L8".replace(/\d/i, "E"); // LE "L8".replace(/\D/i, "E"); // E8 "LLLLL8".replace(/\D/i, "E"); // ELLLL8

You should note that only the first matched character is replaced in the third case. You can also use flags to replace all the matches. We will learn about such flags later.

Just like \d and \D, there are other special character sequences as well.

  1. You can use \w to match any "word" character in a string. Here, word character refers to A-Z, a-z, 0-9, and _. So, basically, it will match all digits, all lowercase and uppercase alphabets, and the underscore.
  2. You can use \W to match any non-word character in a string. It will match characters like %, $, #, ₹, etc.
  3. You can use \s to match a single white space character, which includes space, tab, form feed, and line feed. Similarly, you can use \S to match all other characters besides white space.
  4. You can also look for a specific white space character using \f, \n, \r, \t, and \v, which stand for form feed, line feed, carriage return, horizontal tab, and vertical tab.

Sometimes, you will face situations where you need to replace a word with its substitute, but only if it is not part of a larger word. For example, consider the following sentence:

"A lot of pineapple images were posted on the app".

In this case, we want to replace the word "app" with "board". However, using a simple regular expression pattern will turn "apple" into "boardle", and the final sentence would become:

"A lot of pineboardle images were posted on the app".

In such cases, you can use another special character sequence: \b. This checks for word boundaries. A word boundary is formed by use of any non-word characters like space, "$", "%", "#", etc. Watch out, though—it also includes accented characters like "ü".

"A lot of pineapple images were posted on the app".replace(/app/, "board"); // A lot of pineboardle images were posted on the app "A lot of pineapple images were posted on the app".replace(/\bapp/, "board"); // A lot of pineapple images were posted on the board

Similarly, you can use \B to match a non-word boundary. For example, you could use \B to only match "app" when it is within another word, like "pineapple".

Matching a Pattern "n" Number of Times

You can use ^ to tell JavaScript to only look at the beginning of the string for a match. Similarly, you can use $ to only look at the end of the string for a match.

You can use * to match the preceding expression 0 or more times. For example, /Ap*/ will match A, Ap, App, Appp, and so on.

In a similar manner, you can use + to match the preceding expression 1 or more times. For example, /Ap+/ will match Ap, App, Appp, and so on. The expression will not match the single A this time.

Sometimes, you only want to match a specific number of occurrences of a given pattern. In such cases, you should use the {n} character sequence, where n is a number. For instance, /Ap{2}/ will match App but not Ap. It will also match the first two 'p's in Appp and leave the third one untouched.

You can use {n,} to match at least 'n' occurrences of a given expression. This means that /Ap{2,}/ will match App but not Ap. It will also match all the 'p's in Apppp and replace them with your replacement string.

You can also use {n,m} to specify a minimum and maximum number and limit the number of times the given expression should be matched. For example, /Ap{2,4}/ will match App, Appp, and Apppp. It will also match the first four 'p's in Apppppp and leave the rest of them untouched.

"Apppppples".replace(/Ap*/, "App"); // Apples "Ales".replace(/Ap*/, "App"); // Apples "Appppples".replace(/Ap{2}/, "Add"); // Addppples "Appppples".replace(/Ap{2,}/, "Add"); // Addles "Appppples".replace(/Ap{2,4}/, "Add"); // AddplesUsing Parentheses to Remember Matches

So far, we have only replaced patterns with a constant string. For example, in the previous section, the replacement we used was always "Add". Sometimes, you will have to look for a pattern match inside the given string and then replace it with a part of the pattern.

Let's say you have to find a word with five or more letters in a string and then add an "s" at the end of the word. In such cases, you will not be able to use a constant string value as a replacement as the final value depends on the matching pattern itself.

"I like Apple".replace(/(\w{5,})/, '$1s'); // I like Apples "I like Banana".replace(/(\w{5,})/, '$1s'); // I like Bananas

This was a simple example, but you can use the same technique to keep more than one matching pattern in memory. The number of sub-patterns in the full match will be determined by the number of parentheses used.

Inside the replacement string, the first sub-match will be identified using $1, the second sub-match will be identified using $2, and so on. Here is another example to further clarify the usage of parentheses.

"I am looking for John and Jason".replace(/(\w+)\sand\s(\w+)/, '$2 and $1'); // I am looking for Jason and JohnUsing Flags With Regular Expressions

As I mentioned in the introduction, one more important feature of regular expressions is the use of special flags to modify how a search is performed. The flags are optional, but you can use them to do things like making a search global or case-insensitive.

These are the four commonly used flags to change how JavaScript searches or replaces a string.

  • g: This flag will perform a global search instead of stopping after the first match.
  • i: This flag will perform a search without checking for an exact case match. For instance, Apple, aPPLe, and apPLE are all treated the same during case-insensitive searches.
  • m: This flag will perform a multi-line search.
  • y: This flag will look for a match in the index indicated by the lastIndex property.

Here are some examples of regular expressions used with flags:

"I ate apples, you ate apples".replace(/apples/, "mangoes"); // "I ate mangoes, you ate apples" "I ate apples, you ate apples".replace(/apples/g, "mangoes"); // "I ate mangoes, you ate mangoes" "I ate apples, you ate APPLES".replace(/apples/, "mangoes"); // "I ate mangoes, you ate APPLES" "I ate apples, you ate APPLES".replace(/apples/gi, "mangoes"); // "I ate mangoes, you ate mangoes" var stickyRegex = /apples/y; stickyRegex.lastIndex = 3; "I ate apples, you ate apples".replace(stickyRegex, "mangoes"); // "I ate apples, you ate apples" var stickyRegex = /apples/y; stickyRegex.lastIndex = 6; "I ate apples, you ate apples".replace(stickyRegex, "mangoes"); // "I ate mangoes, you ate apples" var stickyRegex = /apples/y; stickyRegex.lastIndex = 8; "I ate apples, you ate apples".replace(stickyRegex, "mangoes"); // "I ate apples, you ate apples"Final Thoughts

The purpose of this tutorial was to introduce you to regular expressions in JavaScript and their importance. We began with the basics and then covered backslash and other special characters. We also learned how to check for a repeating pattern in a string and how to remember partial matches in a pattern in order to use them later.

Finally, we learned about commonly used flags which make regular expressions even more powerful. You can learn more about regular expressions in this article on MDN.

If there is anything that you would like me to clarify in this tutorial, feel free to let me know in the comments.

Categories: Web Design

Introduction to Popmotion: Custom Animation Scrubber

14 hours 2 min ago

In the first part of the Popmotion introductory series, we learned how to use time-based animations like tween and keyframes. We also learned how to use those animations on the DOM, using the performant styler.

In part two, we learned how to use pointer tracking and record velocity. We then used that to power the velocity-based animations spring, decay, and physics.

In this final part, we're going to be creating a scrubber widget, and we're going to use it to scrub a keyframes animation. We'll make the widget itself from a combination of pointer tracking as well as spring and decay to give it a more visceral feel than run-of-the-mill scrubbers.

Try it for yourself:

Getting StartedMarkup

First, fork this CodePen for the HTML template. As before, because this is an intermediate tutorial, I won't go through everything.

The main twist of note is that the handle on the scrubber is made up of two div elements: .handle and .handle-hit-area.

.handle is the round blue visual indicator of where the scrubber handle is. We've wrapped it in an invisible hit area element to make grabbing the element easier for touchscreen users.

Import Functions

At the top of your JS panel, import everything we're going to use in this tutorial:

const { easing, keyframes, pointer, decay, spring, styler, transform, listen, value } = popmotion; const { pipe, clamp, conditional, linearSpring, interpolate } = transform;Select Elements

We're going to need three elements in this tutorial. We'll animate the .box, drag and animate the .handle-hit-area, and measure the .range.

Let's also create stylers for the elements we're going to animate:

const box = document.querySelector('.box'); const boxStyler = styler(box); const handle = document.querySelector('.handle-hit-area'); const handleStyler = styler(handle); const range = document.querySelector('.range');Keyframes Animation

For our scrubbable animation, we're going to make the .box move from left to right with keyframes. However, we could just as easily scrub a tween or timeline animation using the same method outlined later in this tutorial.

const boxAnimation = keyframes({ values: [0, -150, 150, 0], easings: [easing.backOut, easing.backOut, easing.easeOut], duration: 2000 }).start(boxStyler.set('x'));

Your animation will now be playing. But we don't want that! Let's pause it for now:

boxAnimation.pause();Dragging the x-axis

It's time to use pointer to drag our scrubber handle. In the previous tutorial, we used both x and y properties, but with a scrubber we only need x.

We prefer to keep our code reusable, and tracking a single pointer axis is quite a common use case. So let's create a new function called, imaginatively, pointerX.

It will work exactly like pointer except it'll take just a single number as its argument and output just a single number (x):

const pointerX = (x) => pointer({ x }).pipe(xy => xy.x);

Here, you can see we're using a method of pointer called pipe. pipe is available on all the Popmotion actions we've seen so far, including keyframes.

pipe accepts multiple functions. When the action is started, all output will be passed through each of these functions in turn, before the update function provided to start fires.

In this case, our function is simply:

xy => xy.x

All it is doing is taking the { x, y } object usually output by pointer and returning just the x axis.

Event Listeners

We need to know if the user has started pressing the handle before we start tracking with our new pointerX function.

In the last tutorial we used the traditional addEventListener function. This time, we're going to use another Popmotion function called listen. listen also provides a pipe method, as well as access to all action methods, but we're not going to use that here.

listen allows us to add event listeners to multiple events with a single function, similar to jQuery. So we can condense the previous four event listeners to two:

listen(handle, 'mousedown touchstart').start(startDrag); listen(document, 'mouseup touchend').start(stopDrag);Move the Handle

We'll be needing the handle's x velocity later on, so let's make it a value, which as we learned in the last tutorial allows us to query velocity. On the line after we define handleStyler, add:

const handleX = value(0, handleStyler.set('x'));

Now we can add our startDrag and stopDrag functions:

const startDrag = () => pointerX(handleX.get()) .start(handleX); const stopDrag = () => handleX.stop();

Right now, the handle can be scrubbed beyond the boundaries of the slider, but we'll come back to this later.

Scrubbing

Now we have a visually functional scrubber, but we're not scrubbing the actual animation.

Every value has a subscribe method. This allows us to attach multiple subscribers to fire when the value changes. We want to seek the keyframes animation whenever handleX updates.

First, measure the slider. On the line after we define range, add:

const rangeWidth = range.getBoundingClientRect().width;

keyframes.seek accepts a progress value as expressed from 0 to 1, whereas our handleX is set with pixel values from 0 to rangeWidth.

We can convert from the pixel measurement to a 0 to 1 range by dividing the current pixel measurement by rangeWidth. On the line after boxAnimation.pause(), add this subscribe method:

handleX.subscribe(v => boxAnimation.seek(v / rangeWidth));

Now, if you play with the scrubber, the animation will scrub successfully!

The Extra MileSpring Boundaries

The scrubber can still be pulled outside the boundaries of the full range. To solve this, we could simply use a clamp function to ensure we don't output values outside of 0, rangeWidth.

Instead, we're going to go the extra step and attach springs to the end of our slider. When a user pulls the handle beyond the permitted range, it will tug back towards it. If the user releases the handle while it's outside the range, we can use a spring animation to snap it back.

We'll make this process a single function that we can provide to the pointerX pipe method. By creating a single, reusable function, we can reuse this piece of code with any Popmotion animation, with configurable ranges and spring strengths.

First, let's apply a spring to the left-most limit. We'll use two transformers, conditional and linearSpring.

const springRange = (min, max, strength) => conditional( v => v < min, linearSpring(strength, min) );

conditional takes two functions, an assertion and a transformer. The assertion receives the provided value and returns either true or false. If it returns true, the second function will be provided the value to transform and return.

In this case, the assertion is saying, "If the provided value is smaller than min, pass this value through the linearSpring transformer." The linearSpring is a simple spring function that, unlike the physics or spring animations, has no concept of time. Provide it a strength and a target, and it will create a function that "attracts" any given value towards the target with the defined strength.

Replace our startDrag function with this:

const startDrag = () => pointerX(handleX.get()) .pipe(springRange(0, rangeWidth, 0.1)) .start(handleX);

We're now passing the pointer's x offset through our springRange function, so if you drag the handle past the left-most side, you'll notice it tugs back.

Applying the same to the right-most side is a matter of composing a second conditional with the first using the stand-alone pipe function:

const springRange = (min, max, strength) => pipe( conditional( v => v < min, linearSpring(strength, min) ), conditional( v => v > max, linearSpring(strength, max) ) );

Another benefit of composing a function like springRange is that it becomes very testable. The function it returns is, like all transformers, a pure function that takes a single value. You can test this function to see if it passes through values that lie within min and max unaltered, and if it applies springs to values that lie without.

If you let go of the handle while it lies outside the range, it should now spring back to within range. For that, we'll need to adjust the stopDrag function to fire a spring animation:

const stopDrag = () => { const x = handleX.get(); (x < 0 || x > rangeWidth) ? snapHandleToEnd(x) : handleX.stop(); };

Our snapHandleToEnd function looks like this:

const snapHandleToEnd = (x) => spring({ from: x, velocity: handleX.getVelocity(), to: x < 0 ? 0 : rangeWidth, damping: 30, stiffness: 5000 }).start(handleX);

You can see that to is set either as 0 or rangeWidth depending on which side of the slider the handle currently sits. By playing with damping and stiffness, you can play with a range of different spring-feels.

Momentum Scrolling

A nice touch on iOS scrubber that I always appreciated was that if you threw the handle, it would gradually slow down rather than come to a dead stop. We can replicate that easily using the decay animation.

In stopDrag, replace handleX.stop() with momentumScroll(x).

Then, on the line after the snapHandleToEnd function, add a new function called momentumScroll:

const momentumScroll = (x) => decay({ from: x, velocity: handleX.getVelocity() }).start(handleX);

Now, if you throw the handle, it will come to a gradual stop. It will also animate outside the range of the slider. We can stop this by passing the clamp transformer to the decay.pipe method:

const momentumScroll = (x) => decay({ from: x, velocity: handleX.getVelocity() }).pipe(clamp(0, rangeWidth)) .start(handleX);Conclusion

Using a combination of different Popmotion functions, we can create a scrubber that has a bit more life and playfulness than the usual.

By using pipe, we compose simple pure functions into more complex behaviours while leaving the composite pieces testable and reusable.

Next Steps

How about trying these challenges:

  • Make the momentum scroll end with a bounce if the handle hits either end of the scrubber.
  • Make the handle animate to any point on the scrubber when a user clicks on another part of the range bar.
  • Add full play controls, like a play/pause button. Update the scrubber handle position as the animation progresses.
Categories: Web Design

Introduction to Popmotion: Pointers and Physics

Wed, 05/23/2018 - 05:32

Welcome back to the Introduction to Popmotion tutorial series. In part 1, we discovered how to use tweens and keyframes to make precise, time-scheduled animations.

In Part 2, we're going to look at pointer tracking and velocity-based animations.

Pointer tracking allows us to create scrollable product shelves, custom value sliders, or drag-and-drop interfaces.

Velocity-based animations are different to a time-based animation like tween in that the primary property that affects how the animation behaves is velocity. The animation itself might take any amount of time.

We'll look at the three velocity-based animations in Popmotion, spring, decay, and physics. We'll use the velocity of the pointer tracking animation to start these animations, and that'll demonstrate how velocity-based animations can create engaging and playful UIs in a way that time-based animations simply can't.

First, open this CodePen to play along.

Pointer Tracking

Popmotion provides the pointer function to track and output the coordinates of either a mouse or single touch pointer.

Let's import this along with styler, which will allow us to set the position of the ball.

const { pointer, styler } = popmotion; const ball = document.querySelector('.ball'); const ballStyler = styler(ball);

For this example, we want to drag the ball. Let's add an event that will output the pointer's position to the ball:

let pointerTracker; const startTracking = () => { pointerTracker = pointer().start(ballStyler.set); }; ball.addEventListener('mousedown', startTracking); ball.addEventListener('touchstart', startTracking);

We'll also want some code to stop tracking when we release the ball:

const stopTracking = () => pointerTracker && pointerTracker.stop(); document.addEventListener('mouseup', stopTracking); document.addEventListener('touchend', stopTracking);

If you try and drag the ball now, there's an obvious problem. The ball jumps away when we touch it! Not a great user experience.

This is because, by default, pointer outputs the pointer's position relative to the page.

To output the pointer's position relative to another point, in this case the ball's x/y transform, we can simply pass that position to pointer like this:

const startTracking = () => { pointerTracker = pointer({ x: ballStyler.get('x'), y: ballStyler.get('y') }).start(ballStyler.set); };

Now you've made the ball, in very few lines of code, draggable! However, when the user releases the ball, it stops dead.

This isn't satisfying: Imagine a scrollable carousel of products that a user can drag to scroll. If it just stopped dead instead of momentum scrolling, it'd be less pleasurable to use.

It'd be harder, too, because the overall physical effort needed to scroll the carousel would be higher.

To enable animations like this, we first need to know the velocity of the object being thrown.

Track Velocity

Popmotion provides a function that can help us track velocity. It's called value. Let's import that:

const { pointer, styler, value } = popmotion;

To speak technically for a moment, all of Popmotion's animations are known as actions. Actions are reactive streams of values that can be started and stopped.

A value is, conversely, a reaction. It can't be stopped or started. It just passively responds when its update method is called. It can keep track of values and can be used to query their velocity.

So, after we define ballStyler, let's define a new value for ballXY:

const ballXY = value({ x: 0, y: 0 });

Whenever ballXY updates, we want to update ballStyler. We can pass a second argument to value, a function that will run whenever ballXY updates:

const ballXY = value({ x: 0, y: 0 }, ballStyler.set);

Now we can rewrite our pointer to update ballXY instead of ballStyler.set:

const startTracking = () => { pointer(ballXY.get()) .start(ballXY); };

Now, at any pointer, we can call ballXY.getVelocity() and we'll receive the velocities of both x and y, ready to plug into our velocity-based animations.

Velocity-Based Animations spring

The first velocity-based animation to introduce is spring. It's based on the same equations that govern Apple's CASpringAnimation, the spring animation behind all that iOS springy playfulness.

Import:

const { pointer, spring, styler, value } = popmotion;

Now, amend stopTracking so that instead of stopping the pointerTracker animation, it starts a spring animation like this:

const stopTracking = () => spring({ from: ballXY.get(), velocity: ballXY.getVelocity(), to: 0, stiffness: 100, damping: 20 }).start(ballXY);

We provide it with the ball's current position, its velocity, and a target, and the simulation is run. It changes depending on how the user has thrown the ball.

The cool thing about springs is they're expressive. By adjusting the mass, stiffness and damping properties, you can end up with radically different spring-feels.

For instance, if you only change the stiffness above to 1000, you can create a motion that feels like high-energy snapping. Then, by changing mass to 20, you create motion that looks almost like gravity.

There's a combination that will feel right and satisfying for your users, and appropriate to your brand, under almost any circumstance. By playing with different spring-feels, you can communicate different feelings, like a strict out-of-bounds snap or a softer affirmative bounce.

decay

The decay animation, as the name suggests, decays the provided velocity so that the animation gradually slows to a complete stop.

This can be used to create the momentum scrolling effect found on smartphones, like this:

Import the decay function:

const { decay, pointer, spring, styler, value } = popmotion;

And replace the stopTracking function with the following:

const stopTracking = () => decay({ from: ballXY.get(), velocity: ballXY.getVelocity() }).start(ballXY);

decay automatically calculates a new target based on the provided from and velocity props.

It's possible to adjust the feel of the deceleration by messing with the props outlined in the docs linked above but, unlike spring and physics, decay is designed to work out of the box. 

physics

Finally, we have the physics animation. This is Popmotion's Swiss Army knife of velocity-based animations. With it, you can simulate:

  • constant velocity
  • acceleration
  • springs
  • friction

spring and decay offer super-precise motion and a wider variety of "feels". Soon, they'll both also be scrubbable.

But both are immutable. Once you've started either, their properties are set in stone. Perfect for when we want to start an animation based on the initial from/velocity state, but not so good if we want ongoing interaction.

physics, instead, is an integrated simulation closer to that of a video game. It works by, once per frame, taking the current state and then modifying it based on the current properties at that point in time.

This allows it to be mutable, which means we can change those properties, which then changes the outcome of the simulation.

To demonstrate this, let's make a twist on classic pointer smoothing, with elastic smoothing.

Import physics:

const { pointer, spring, physics, styler, value } = popmotion;

This time, we're going to change the startTracking function. Instead of changing ballXY with pointer, we'll use physics:

const startTracking = () => { const physicsAnimation = physics({ from: ballXY.get(), to: ballXY.get(), velocity: ballXY.getVelocity(), restSpeed: false, friction: 0.6, springStrength: 400 }).start(ballXY); };

Here, we're setting from and velocity as normal. friction and springStrength both adjust the properties of the spring.

restSpeed: false overrides the default behaviour of the animation stopping when motion stops. We want to stop it manually in stopTracking.

On its own, this animation won't do anything because we set to, the spring's target, to the same as from. So let's reimplement the pointer tracking this time to change the spring target of physics. On the last line of startTracking, add:

pointerTracker = pointer(ballXY.get()).start((v) => { physicsAnimation.setSpringTarget(v); });

Here, we're using a similar pointer animation as before. Except this time, we're using it to change the target of another animation. In doing so, we create this elasticated pointer tracking:

Conclusion

Velocity-based animations paired with pointer tracking can create engaging and playful interfaces.

spring can be used to create a wide-variety of spring-feels, while decay is specifically tailored for momentum scroll animations. physics is more limited than either in terms of configurability, but also provides the opportunity to change the simulation in progress, opening new interaction possibilities.

In the next and final part of this introductory series on Popmotion, we're going to take everything we've learned in the first two parts and use them along with some light functional composition to create a scrubbable animation, along with a scrubber to do the scrubbing with!

Categories: Web Design

New Course: Connect to a Database With Laravel's Eloquent ORM

Tue, 05/22/2018 - 04:54
What You'll Be Creating

In our new course, Connect to a Database With Laravel's Eloquent ORM, you'll learn all about Eloquent, which makes it easy to connect to relational data in a database and work with it using object-oriented models in your Laravel app. It is simple to set up, easy to use, and packs a lot of power.

What You’ll Learn

In this course, Envato Tuts+ instructor Jeremy McPeak will teach you how to use Eloquent, Laravel's object-relational mapper (ORM). 

Follow along as Jeremy builds the data back-end for a simple guitar database app. You'll learn how to create data tables with migrations, how to create data models, and how to use Eloquent for querying and mutating data.

Watch the Introduction Take the Course

You can take our new course straight away with a subscription to Envato Elements. For a single low monthly fee, you get access not only to this course, but also to our growing library of over 1,000 video courses and industry-leading eBooks on Envato Tuts+. 

Plus you now get unlimited downloads from the huge Envato Elements library of 580,000+ creative assets. Create with unique fonts, photos, graphics and templates, and deliver better projects faster.

Categories: Web Design

How to Make a Real-Time Sports Application Using Node.js

Fri, 05/18/2018 - 05:32
What You'll Be Creating

In today's article I'm going to demonstrate how to make a web application that will display live game scores from the NHL. The scores will update automatically as the games progress.

This is a very exciting article for me, as it allows me the chance to bring two of my favorite passions together: development and sports.

The technologies that will be used to create the application are:

  1. Node.js
  2. Socket.io
  3. MySportsFeed.com

If you don't have Node.js installed, visit their download page now and set it up before continuing.

What Is Socket.io?

Socket.io is a technology that connects a client to a server. In this example, the client is a web browser and the server is the Node.js application. The server can have multiple clients connected to it at any given time.

Once the connection has been established, the server can send messages to all of the clients or an individual client. In return, the client can send a message to the server, allowing for bi-directional real-time communication.

Before Socket.io, web applications would commonly use AJAX, and both the client and server would poll each other looking for events. For example, every 10 seconds an AJAX call would occur to see if there were any messages to handle.

Polling for messages caused a significant amount of overhead on both the client and server as it would be constantly looking for messages when there were none.

With Socket.io, messages are received instantaneously, without needing to look for messages, reducing the overhead.

Sample Socket.io Application

Before we consume the real-time sports data, let's create an example application to demonstrate how Socket.io works.

To begin, I am going to create a new Node.js application. In a console window, I am going to navigate to C:\GitHub\NodeJS, create a new folder for my application, and create a new application:

cd \GitHub\NodeJS mkdir SocketExample cd SocketExample npm init

I used all the default settings.

Because we are making a web application, I'm going use an NPM package called Express to simplify the setup. In a command prompt, install it as follows: npm install express --save

And of course we will need to install the Socket.io package: npm install socket.io --save

Let's begin by creating the web server. Create a new file called index.js and place the following code within it to create the web server using Express:

var app = require('express')(); var http = require('http').Server(app); app.get('/', function(req, res){ res.sendFile(__dirname + '/index.html'); }); http.listen(3000, function(){ console.log('HTTP server started on port 3000'); });

If you are not familiar with Express, the above code example includes the Express library and creates a new HTTP server. In this example, the HTTP server is listening on port 3000, e.g. http://localhost:3000. A route is created at the root of the site "/". The result of the route returns an HTML file: index.html.

Before we create the index.html file, let's finish the server by setting up Socket.io. Append the following to your index.js file to create the Socket server:

var io = require('socket.io')(http); io.on('connection', function(socket){ console.log('Client connection received'); });

Similar to Express, the code begins by importing the Socket.io library. This is stored in a variable called io. Next, using the io variable, an event handler is created with the on function. The event being listened for is connection. This event is called each time a client connects to the server.

Let's now create our very basic client. Create a new file called index.html and place the following code within:

<!doctype html> <html> <head> <title>Socket.IO Example</title> </head> <body> <script src="/socket.io/socket.io.js"></script> <script> var socket = io(); </script> </body> </html>

The HTML above loads the Socket.io client JavaScript and initializes a connection to the server. To see the example, start your Node application: node index.js

Then, in your browser, navigate to http://localhost:3000. Nothing will appear on the page; however, if you look at the console where the Node application is running, two messages are logged:

  1. HTTP server started on port 3000
  2. Client connection received

Now that we have a successful socket connection, let's put it to use. Let's begin by sending a message from the server to the client. Then, when the client receives the message, it can send a response back to the server.

Let's look at the abbreviated index.js file:

io.on('connection', function(socket){ console.log('Client connection received'); socket.emit('sendToClient', { hello: 'world' }); socket.on('receivedFromClient', function (data) { console.log(data); }); });

The previous io.on function has been updated to include a few new lines of code. The first, socket.emit, sends the message to the client. The sendToClient is the name of the event. By naming events, you can send different types of messages so the client can interpret them differently. The second addition is the socket.on, which also contains an event name: receivedFromClient. This creates a function that accepts data from the client. In this case, the data is logged to the console window.

That completes the server-side amendments; it can now send and receive data from any connected clients.

Let's complete this example by updating the client to receive the sendToClient event. When it receives the event, it can respond with the receivedFromClient event back to the server.

This is accomplished in the JavaScript portion of the HTML, so in the index.html file, I have updated the JavaScript as follows:

var socket = io(); socket.on('sendToClient', function (data) { console.log(data); socket.emit('receivedFromClient', { my: 'data' }); });

Using the instantiated socket variable, we have very similar logic on the server with a socket.on function. For the client, it is listening to the sendToClient event. As soon as the client is connected, the server sends this message. When the client receives it, it is logged to the console in the browser. The client then uses the same socket.emit that the server used to send the original event. In this instance, the client sends back the receivedFromClient event to the server. When the server receives the message, it is logged to the console window.

Try it out for yourself. First, in a console, run your Node application: node index.js. Then load http://localhost:3000 in your browser.

Check the web browser console and you should see the following JSON data logged: {hello: "world"}

Then, in the command prompt where the Node application is running, you should see the following:

HTTP server started on port 3000 Client connection received { my: 'data' }

Both the client and server can use the JSON data received to perform specific tasks. We will learn more about that once we connect to the real-time sports data.

Sports Data

Now that we have mastered how to send and receive data to and from the client and server, this can be leveraged to provide real-time updates. I chose to use sports data, although the same theory is not limited to sports. Before I began this project, I researched different sports data. The one I settled on, because they offer free developer accounts, was MySportsFeeds (I am not affiliated with them in any way). To access the real-time data, I signed up for an account and then made a small donation. Donations start at $1 to have data updated every 10 minutes. This will be good for the example.

Once your account is set up, you can proceed to setting up access to their API. To assist with this, I am going to use their NPM package: npm install mysportsfeeds-node --save

After the package has been installed, API calls can be made as follows:

var MySportsFeeds = require("mysportsfeeds-node"); var msf = new MySportsFeeds("1.2", true); msf.authenticate("********", "*********"); var today = new Date(); msf.getData('nhl', '2017-2018-regular', 'scoreboard', 'json', { fordate: today.getFullYear() + ('0' + parseInt(today.getMonth() + 1)).slice(-2) + ('0' + today.getDate()).slice(-2), force: true });

In the example above, be sure to replace the call to the authenticate function with your username and password.

The following code executes an API call to the get the NHL scoreboard for today. The fordate variable is what specifies today. I've also set force to true so that a response is always returned, even when the data has not changed.

With the current setup, the results of the API call get written to a text file. In the final example, this will be changed; however, for demonstration purposes, the results file can be reviewed in a text editor to understand the contents of the response. The results contain a scoreboard object. This object contains an array called gameScore. This object stores the result of each game. Each object contains a child object called game. This object provides the information about who is playing.

Outside of the game object, there are a handful of variables that provide the current state of the game. The data changes based on the state of the game. For example, when the game hasn't started, there are only a few variables that tell us the game is not in progress and has not started.

When the game is in progress, additional data is provided about the score, what period the game is in, and how much time is remaining. We will see this in action when we get to the HTML to show the game in the next section.

Real-Time Updates

We have all the pieces to the puzzle, so it is now time to put the puzzle together to reveal the final picture. Currently, MySportsFeeds has limited support for pushing data to us, so we will have to poll the data from them. Luckily, we know the data only changes once every 10 minutes, so we don't need to add overhead by polling for changes too frequently. Once we poll the data from them, we can push those updates from the server to all clients connected.

To perform the polling, I will use the JavaScript setInterval function to call the API (in my case) every 10 minutes to look for updates. When the data is received, an event is sent to all of the connected clients. When the clients receive the event, the game scores will be updated with JavaScript in the web browser.

MySportsFeeds will also be called when the Node application first starts up. This data will be used for any clients who connect before the first 10-minute interval. This is stored in a global variable. This same global variable is updated as part of the interval polling. This will ensure that when any new clients connect after the polling, they will have the latest data.

To assist with some code cleanliness in the main index.js file, I have created a new file called data.js. This file will contain a function that is exported (available in the index.js file) that performs the previous call to the MySportsFeeds API. Here are the full contents of that file:

var MySportsFeeds = require("mysportsfeeds-node"); var msf = new MySportsFeeds("1.2", true, null); msf.authenticate("*******", "******"); var today = new Date(); exports.getData = function() { return msf.getData('nhl', '2017-2018-regular', 'scoreboard', 'json', { fordate: today.getFullYear() + ('0' + parseInt(today.getMonth() + 1)).slice(-2) + ('0' + today.getDate()).slice(-2), force: true }); };

A getData function is exported and returns the result of the call, which in this case is a Promise that will be resolved in the main application.

Now let's look at the final contents of the index.js file:

var app = require('express')(); var http = require('http').Server(app); var io = require('socket.io')(http); var data = require('./data.js'); // Global variable to store the latest NHL results var latestData; // Load the NHL data for when client's first connect // This will be updated every 10 minutes data.getData().then((result) => { latestData = result; }); app.get('/', function(req, res){ res.sendFile(__dirname + '/index.html'); }); http.listen(3000, function(){ console.log('HTTP server started on port 3000'); }); io.on('connection', function(socket){ // when clients connect, send the latest data socket.emit('data', latestData); }); // refresh data setInterval(function() { data.getData().then((result) => { // Update latest results for when new client's connect latestData = result; // send it to all connected clients io.emit('data', result); console.log('Last updated: ' + new Date()); }); }, 300000);

The first seven lines of code above instantiate the required libraries and the global latestData variable. The final list of libraries used are: Express, Http Server created with Express, Socket.io, and the aforementioned data.js file just created.

With the necessities taken care of, the application populates the latestData for clients who will connect when the server is first started:

// Global variable to store the latest NHL results var latestData; // Load the NHL data for when client's first connect // This will be updated every 10 minutes data.getData().then((result) => { latestData = result; });

The next few lines set up a route for the root page of the website (http://localhost:3000/) and start the HTTP server to listen on port 3000.

Next, the Socket.io is set up to look for connections. When a new connection is received, the server emits an event called data with the contents of the latestData variable.

And finally, the final chunk of code creates the polling interval. When the interval occurs, the latestData variable is updated with the results of the API call. This data then emits the same data event to all clients.

// refresh data setInterval(function() { data.getData().then((result) => { // Update latest results for when new client's connect latestData = result; // send it to all connected clients io.emit('data', result); console.log('Last updated: ' + new Date()); }); }, 300000);

You may notice that when the client connects and an event is emitted, it is emitting the event with the socket variable. This approach will send the event to that connected client only. Inside the interval, the global io is used to emit the event. This will send the event to all clients.

That completes the server. Let's work on the client front-end. In an earlier example, I created a basic index.html file that set up the client connection that would log events from the server and send one back. I am going to extend that file to contain the completed example.

Because the server is sending us a JSON object, I am going to use jQuery and leverage a jQuery extension called JsRender. This is a templating library. It will allow me to create a template with HTML that will be used to display the contents of each NHL game in an easy-to-use, consistent manner. In a moment, you will see the power of this library. The final code is over 40 lines of code, so I am going to break it down into smaller chunks, and then display the full HTML together at the end.

This first part creates the template that will be used to show the game data:

<script id="gameTemplate" type="text/x-jsrender"> <div class="game"> <div> {{:game.awayTeam.City}} {{:game.awayTeam.Name}} at {{:game.homeTeam.City}} {{:game.homeTeam.Name}} </div> <div> {{if isUnplayed == "true" }} Game starts at {{:game.time}} {{else isCompleted == "false"}} <div>Current Score: {{:awayScore}} - {{:homeScore}}</div> <div> {{if currentIntermission}} {{:~ordinal_suffix_of(currentIntermission)}} Intermission {{else currentPeriod}} {{:~ordinal_suffix_of(currentPeriod)}}<br/> {{:~time_left(currentPeriodSecondsRemaining)}} {{else}} 1st {{/if}} </div> {{else}} Final Score: {{:awayScore}} - {{:homeScore}} {{/if}} </div> </div> </script>

The template is defined using a script tag. It contains the id of the template and a special script type called text/x-jsrender. The template defines a container div for each game that contains a class game to apply some basic styling. Inside this div, the templating begins.

In the next div, the away and home team are displayed. This is done by concatenating the city and team name together from the game object from the MySportsFeed data.

{{:game.awayTeam.City}} is how I define an object that will be replaced with a physical value when the template is rendered. This syntax is defined by the JsRender library.

Once the teams are displayed, the next chunk of code does some conditional logic. When the game is unPlayed, a string will be outputted that the game will start at {{:game.time}}.

When the game is not completed, the current score is displayed: Current Score: {{:awayScore}} - {{:homeScore}}. And finally, some tricky little logic to identify what period the hockey game is in or if it is in intermission.

If the variable currentIntermission is provided in the results, then I use a function I defined called ordinal_suffix_of, which will convert the period number to read: 1st (2nd, 3rd, etc.) Intermission.

When it is not in intermission, I look for the currentPeriod value. This also uses the ordinal_suffix_of  to show that the game is in the 1st (2nd, 3rd, etc.) period.

Beneath this, another function I defined called time_left is used to convert the number of seconds remaining into the number of minutes and seconds remaining in the period. For example: 10:12.

The final part of the code displays the final score because we know the game has completed.

Here is an example of what it looks like when there is a mix of finished games, in progress games, and games that have not started yet (I'm not a very good designer, so it looks as you would expect when a developer makes their own User Interface).

Next up is a chunk of JavaScript that creates the socket, the helper functions ordinal_suffix_of and time_left, and a variable that references the jQuery template created.

<script> var socket = io(); var tmpl = $.templates("#gameTemplate"); var helpers = { ordinal_suffix_of: function(i) { var j = i % 10, k = i % 100; if (j == 1 && k != 11) { return i + "st"; } if (j == 2 && k != 12) { return i + "nd"; } if (j == 3 && k != 13) { return i + "rd"; } return i + "th"; }, time_left: function(time) { var minutes = Math.floor(time / 60); var seconds = time - minutes * 60; return minutes + ':' + ('0' + seconds).slice(-2); } }; </script>

The final piece of code is the code to receive the socket event and render the template:

socket.on('data', function (data) { console.log(data); $('#data').html(tmpl.render(data.scoreboard.gameScore, helpers)); });

I have a placeholder div with the id of data. The result of the template rendering (tmpl.render) writes the HTML to this container. What is really neat is that the JsRender library can accept an array of data, in this case data.scoreboard.gameScore, that iterates through each element in the array and creates one game per element.

Here is the final HTML and JavaScript all together:

<!doctype html> <html> <head> <title>Socket.IO Example</title> </head> <body> <div id="data"> </div> <script id="gameTemplate" type="text/x-jsrender"> <div class="game"> <div> {{:game.awayTeam.City}} {{:game.awayTeam.Name}} at {{:game.homeTeam.City}} {{:game.homeTeam.Name}} </div> <div> {{if isUnplayed == "true" }} Game starts at {{:game.time}} {{else isCompleted == "false"}} <div>Current Score: {{:awayScore}} - {{:homeScore}}</div> <div> {{if currentIntermission}} {{:~ordinal_suffix_of(currentIntermission)}} Intermission {{else currentPeriod}} {{:~ordinal_suffix_of(currentPeriod)}}<br/> {{:~time_left(currentPeriodSecondsRemaining)}} {{else}} 1st {{/if}} </div> {{else}} Final Score: {{:awayScore}} - {{:homeScore}} {{/if}} </div> </div> </script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jsrender/0.9.90/jsrender.min.js"></script> <script src="/socket.io/socket.io.js"></script> <script> var socket = io(); var helpers = { ordinal_suffix_of: function(i) { var j = i % 10, k = i % 100; if (j == 1 && k != 11) { return i + "st"; } if (j == 2 && k != 12) { return i + "nd"; } if (j == 3 && k != 13) { return i + "rd"; } return i + "th"; }, time_left: function(time) { var minutes = Math.floor(time / 60); var seconds = time - minutes * 60; return minutes + ':' + ('0' + seconds).slice(-2); } }; var tmpl = $.templates("#gameTemplate"); socket.on('data', function (data) { console.log(data); $('#data').html(tmpl.render(data.scoreboard.gameScore, helpers)); }); </script> <style> .game { border: 1px solid #000; float: left; margin: 1%; padding: 1em; width: 25%; } </style> </body> </html>

Start the Node application and browse to http://localhost:3000 to see the results for yourself!

Every X minutes, the server will send an event to the client. The client will redraw the game elements with the updated data. So when you leave the site open and periodically look at it, you will see the game data refresh when games are currently in progress.

Conclusion

The final product uses Socket.io to create a server that clients connect to. The server fetches data and sends it to the client. When the client receives the data, it can seamlessly update the display. This reduces load on the server because the client only performs work when it receives an event from the server.

Sockets are not limited to one direction; the client can also send messages to the server. When the server receives the message, it can perform some processing.

Chat applications would commonly work this way. The server would receive a message from the client and then broadcast to all connected clients to show that someone has sent a new message.

Hopefully you enjoyed this article as I had a blast creating this real-time sports application for one of my favorite sports!

Categories: Web Design

How to Create a Custom Settings Panel in WooCommerce

Fri, 05/11/2018 - 05:29
What You'll Be Creating

WooCommerce is by far the leading ecommerce plugin for WordPress. At the time of writing, it has over 3 million active installations and is reportedly behind over 40% of all online stores.

One of the reasons for WooCommerce's popularity is its extendability. Like WordPress itself, WooCommerce is packed full of actions and filters that developers can hook into if they want to extend WooCommerce's default functionality.

A great example of this is the ability to create a custom data panel.

What's Covered in This Tutorial?

This tutorial is split into two parts. In part one, we're going to be looking at:

  • adding a custom panel to WooCommerce
  • adding custom fields to the panel
  • sanitizing and saving custom field values

Then in part two, we'll look at:

  • displaying custom fields on the product page
  • changing the product price depending on the value of custom fields
  • displaying custom field values in the cart and order
What Is a WooCommerce Custom Data Panel?

When you create a new product in WooCommerce, you enter most of the critical product information, like price and inventory, in the Product data section.

In the screenshot above, you can see that the Product data section is divided into panels: the tabs down the left, e.g. General, Inventory, etc., each open different panels in the main view on the right.

In this tutorial, we're going to look at creating a custom panel for product data and adding some custom fields to it. Then we'll look at using those custom fields on the front end and saving their values to customer orders.

In our example scenario, we're going to add a 'Giftwrap' panel which contains some custom fields:

  • a checkbox to include a giftwrapping option for the product on the product page
  • a checkbox to enable an input field where a customer can enter a message on the product page
  • an input field to add a price for the giftwrapping option; the price will be added to the product price in the cart

In the back end, it's going to look like this:

And on the front end, it will look something like this:

Create a New Plugin

Because we're extending functionality, we're going to create a plugin rather than adding our code to a theme. That means that our users will be able to retain this extra functionality even if they switch their site's theme. Creating a plugin is out of scope for this tutorial, but if you need some help, take a look at this Tuts+ Coffee Break Course on creating your first plugin: 

Our plugin is going to consist of two classes: one to handle stuff in the admin, and one to handle everything on the front end. Our plugin file structure is going to look like this:

Admin Class

First up, we need to create our class to handle everything on the back end. In a folder called classes, create a new file called class-tpwcp-admin.php.

This class will handle the following:

  • Create the custom tab (the tab is the clickable element down the left of the Product data section).
  • Add the custom fields to the custom panel (the panel is the element that's displayed when you click a tab).
  • Decide the product types where the panel will be enabled.
  • Sanitize and save the custom field values.

Paste the following code into that new file. We'll walk through it step by step afterwards.

<?php /** * Class to create additional product panel in admin * @package TPWCP */ // Exit if accessed directly if( ! defined( 'ABSPATH' ) ) { exit; } if( ! class_exists( 'TPWCP_Admin' ) ) { class TPWCP_Admin { public function __construct() { } public function init() { // Create the custom tab add_filter( 'woocommerce_product_data_tabs', array( $this, 'create_giftwrap_tab' ) ); // Add the custom fields add_action( 'woocommerce_product_data_panels', array( $this, 'display_giftwrap_fields' ) ); // Save the custom fields add_action( 'woocommerce_process_product_meta', array( $this, 'save_fields' ) ); } /** * Add the new tab to the $tabs array * @see https://github.com/woocommerce/woocommerce/blob/e1a82a412773c932e76b855a97bd5ce9dedf9c44/includes/admin/meta-boxes/class-wc-meta-box-product-data.php * @param $tabs * @since 1.0.0 */ public function create_giftwrap_tab( $tabs ) { $tabs['giftwrap'] = array( 'label' => __( 'Giftwrap', 'tpwcp' ), // The name of your panel 'target' => 'gifwrap_panel', // Will be used to create an anchor link so needs to be unique 'class' => array( 'giftwrap_tab', 'show_if_simple', 'show_if_variable' ), // Class for your panel tab - helps hide/show depending on product type 'priority' => 80, // Where your panel will appear. By default, 70 is last item ); return $tabs; } /** * Display fields for the new panel * @see https://docs.woocommerce.com/wc-apidocs/source-function-woocommerce_wp_checkbox.html * @since 1.0.0 */ public function display_giftwrap_fields() { ?> <div id='gifwrap_panel' class='panel woocommerce_options_panel'> <div class="options_group"> <?php woocommerce_wp_checkbox( array( 'id' => 'include_giftwrap_option', 'label' => __( 'Include giftwrap option', 'tpwcp' ), 'desc_tip' => __( 'Select this option to show giftwrapping options for this product', 'tpwcp' ) ) ); woocommerce_wp_checkbox( array( 'id' => 'include_custom_message', 'label' => __( 'Include custom message', 'tpwcp' ), 'desc_tip' => __( 'Select this option to allow customers to include a custom message', 'tpwcp' ) ) ); woocommerce_wp_text_input( array( 'id' => 'giftwrap_cost', 'label' => __( 'Giftwrap cost', 'tpwcp' ), 'type' => 'number', 'desc_tip' => __( 'Enter the cost of giftwrapping this product', 'tpwcp' ) ) ); ?> </div> </div> <?php } /** * Save the custom fields using CRUD method * @param $post_id * @since 1.0.0 */ public function save_fields( $post_id ) { $product = wc_get_product( $post_id ); // Save the include_giftwrap_option setting $include_giftwrap_option = isset( $_POST['include_giftwrap_option'] ) ? 'yes' : 'no'; // update_post_meta( $post_id, 'include_giftwrap_option', sanitize_text_field( $include_giftwrap_option ) ); $product->update_meta_data( 'include_giftwrap_option', sanitize_text_field( $include_giftwrap_option ) ); // Save the include_giftwrap_option setting $include_custom_message = isset( $_POST['include_custom_message'] ) ? 'yes' : 'no'; $product->update_meta_data( 'include_custom_message', sanitize_text_field( $include_custom_message ) ); // Save the giftwrap_cost setting $giftwrap_cost = isset( $_POST['giftwrap_cost'] ) ? $_POST['giftwrap_cost'] : ''; $product->update_meta_data( 'giftwrap_cost', sanitize_text_field( $giftwrap_cost ) ); $product->save(); } } } Create the Custom Tab

To create the custom tab, we hook into the woocommerce_product_data_tabs filter using our create_giftwrap_tab function. This passes the WooCommerce $tabs object in, which we then modify using the following parameters:

  • label: use this to define the name of your tab.
  • target: this is used to create an anchor link so needs to be unique.
  • class: an array of classes that will be applied to your panel.
  • priority: define where you want your tab to appear.

Product Types

At this stage, it's worth considering what product types we'd like our panel to be enabled for. By default, there are four WooCommerce product types: simple, variable, grouped, and affiliate. Let's say for our example scenario, we only want our Giftwrap panel to be enabled for simple and variable product types.

To achieve this, we add the show_if_simple and show_if_variable classes to the class parameter above. If we didn't want to enable the panel for variable product types, we'd just omit the show_if_variable class.

Add Custom Fields

The next hook we use is woocommerce_product_data_panels. This action allows us to output our own markup for the Giftwrap panel. In our class, the function display_giftwrap_fields creates a couple of div wrappers, inside which we use some WooCommerce functions to create custom fields. 

Note how the id attribute for our outer div, giftwrap_panel, matches the value we passed into the target parameter of our giftwrap tab above. This is how WooCommerce will know to display this panel when we click the Giftwrap tab.

WooCommerce Custom Field Functions

In our example, the two functions we're using to create our fields are:

  • woocommerce_wp_checkbox
  • woocommerce_wp_text_input

These functions are provided by WooCommerce specifically for the purpose of creating custom fields. They take an array of arguments, including:

  • id: this is the ID of your field. It needs to be unique, and we'll be referencing it later in our code.
  • label: this is the label as it will appear to the user.
  • desc_tip: this is the optional tool tip that appears when the user hovers over the question mark icon next to the label.

Note also that the woocommerce_wp_text_input function also takes a type argument, where you can specify number for a number input field, or text for a text input field. Our field will be used to input a price, so we specify it as number.

Save the Custom Fields

The final part of our admin class uses the woocommerce_process_product_meta action to save our custom field values.

In order to standardize and optimize how it stores and retrieves data, WooCommerce 3.0 adopted a CRUD (Create, Read, Update, Delete) method for setting and getting product data. You can find out more about the thinking behind this in the WooCommerce 3.0 announcement.

With this in mind, instead of the more familiar get_post_meta and update_post_meta methods that we might have used in the past, we now use the $post_id to create a WooCommerce $product object, and then apply the update_meta_data method to save data. For example:

$product = wc_get_product( $post_id ); $include_giftwrap_option = isset( $_POST['include_giftwrap_option'] ) ? 'yes' : 'no'; $product->update_meta_data( 'include_giftwrap_option', sanitize_text_field( $include_giftwrap_option ) ); $product->save();

Please note also that we're careful to sanitize our data before saving it to the database. There's more information on sanitizing data here: 

Main Plugin File

When you've created your readme.txt file and your main plugin file tutsplus-woocommerce-panel.php, you can add this code to your main file.

<?php /** * Plugin Name: Tutsplus WooCommerce Panel * Description: Add a giftwrap panel to WooCommerce products * Version: 1.0.0 * Author: Gareth Harris * Author URI: https://catapultthemes.com/ * Text Domain: tpwcp * WC requires at least: 3.2.0 * WC tested up to: 3.3.0 * License: GPL-2.0+ * License URI: http://www.gnu.org/licenses/gpl-2.0.txt */ // Exit if accessed directly if ( ! defined( 'ABSPATH' ) ) { exit; } /** * Define constants */ if ( ! defined( 'TPWCP_PLUGIN_VERSION' ) ) { define( 'TPWCP_PLUGIN_VERSION', '1.0.0' ); } if ( ! defined( 'TPWCP_PLUGIN_DIR_PATH' ) ) { define( 'TPWCP_PLUGIN_DIR_PATH', plugin_dir_path( __FILE__ ) ); } require( TPWCP_PLUGIN_DIR_PATH . '/classes/class-tpwcp-admin.php' ); /** * Start the plugin. */ function tpwcp_init() { if ( is_admin() ) { $TPWCP = new TPWCP_Admin(); $TPWCP->init(); } } add_action( 'plugins_loaded', 'tpwcp_init' );

This will initiate your admin class.

When you activate your plugin on a site (along with WooCommerce) and then go to create a new product, you'll see your new Giftwrap panel available, along with custom fields. You can update the fields and save them... But you won't see anything on the front end yet.

Conclusion

Let's just recap what we've looked at so far in this article.

We've looked at an example scenario for adding a custom 'Giftwrap' panel to WooCommerce. We've created a plugin and added a class to create the panel. Within the class, we've also used WooCommerce functions to add custom fields, and then we've sanitized and saved those field values.

Categories: Web Design

How Laravel Broadcasting Works

Mon, 05/07/2018 - 05:26

Today, we are going to explore the concept of broadcasting in the Laravel web framework. It allows you to send notifications to the client side when something happens on the server side. In this article, we are going to use the third-party Pusher library to send notifications to the client side.

If you have ever wanted to send notifications from the server to the client when something happens on a server in Laravel, you're looking for the broadcasting feature.

For example, let's assume that you've implemented a messaging application that allows users of your system to send messages to each other. Now, when user A sends a message to user B, you want to notify user B in real time. You may display a popup or an alert box that informs user B about the new message!

It's the perfect use-case to walk through the concept of broadcasting in Laravel, and that's what we'll implement in this article.

If you are wondering how the server could send notifications to the client, it's using sockets under the hood to accomplish it. Let's understand the basic flow of sockets before we dive deeper into the actual implementation.

  • Firstly, you need a server that supports the web-sockets protocol and allows the client to establish a web socket connection.
  • You could implement your own server or use a third-party service like Pusher. We'll prefer the latter in this article.
  • The client initiates a web socket connection to the web socket server and receives a unique identifier upon successful connection.
  • Once the connection is successful, the client subscribes to certain channels at which it would like to receive events.
  • Finally, under the subscribed channel, the client registers events that it would like to listen to.
  • Now on the server side, when a particular event happens, we inform the web-socket server by providing it with the channel name and event name.
  • And finally, the web-socket server broadcasts that event to registered clients on that particular channel.

Don't worry if it looks like too much in a single go; you will get the hang of it as we move through this article.

Next, let's have a look at the default broadcast configuration file at config/broadcasting.php.

<?php return [ /* |-------------------------------------------------------------------------- | Default Broadcaster |-------------------------------------------------------------------------- | | This option controls the default broadcaster that will be used by the | framework when an event needs to be broadcast. You may set this to | any of the connections defined in the "connections" array below. | | Supported: "pusher", "redis", "log", "null" | */ 'default' => env('BROADCAST_DRIVER', 'log'), /* |-------------------------------------------------------------------------- | Broadcast Connections |-------------------------------------------------------------------------- | | Here you may define all of the broadcast connections that will be used | to broadcast events to other systems or over websockets. Samples of | each available type of connection are provided inside this array. | */ 'connections' => [ 'pusher' => [ 'driver' => 'pusher', 'key' => env('PUSHER_APP_KEY'), 'secret' => env('PUSHER_APP_SECRET'), 'app_id' => env('PUSHER_APP_ID'), ], 'redis' => [ 'driver' => 'redis', 'connection' => 'default', ], 'log' => [ 'driver' => 'log', ], 'null' => [ 'driver' => 'null', ], ], ];

By default, Laravel supports multiple broadcast adapters in the core itself.

In this article, we are going to use the Pusher broadcast adapter. For debugging purposes, you could also use the log adapter. Of course, if you're using the log adapter, the client won't receive any event notifications, and it'll only be logged to the laravel.log file.

From the next section onward, we'll right away dive into the actual implementation of the aforementioned use-case.

Setting Up the Prerequisites

In broadcasting, there are different types of channels—public, private, and presence. When you want to broadcast your events publicly, it's the public channel that you are supposed to use. Conversely, the private channel is used when you want to restrict event notifications to certain private channels.

In our use-case, we want to notify users when they get a new message. And to be eligible to receive broadcast notifications, the user must be logged in. Thus, we'll need to use the private channel in our case.

Core Authentication Feature

Firstly, you need to enable the default Laravel authentication system so that features like registration, login and the like work out of the box. If you're not sure how to do that, the official documentation provides a quick insight into that.

Pusher SDK—Installation and Configuration

As we're going to use the Pusher third-party service as our web-socket server, you need to create an account with it and make sure you have the necessary API credentials with your post registration. If you're facing any trouble creating it, don't hesitate to ask me in the comment section.

Next, we need to install the Pusher PHP SDK so that our Laravel application can send broadcast notifications to the Pusher web-socket server.

In your Laravel application root, run the following command to install it as a composer package.

$composer require pusher/pusher-php-server "~3.0"

Now, let's change the broadcast configuration file to enable the Pusher adapter as our default broadcast driver.

<?php return [ /* |-------------------------------------------------------------------------- | Default Broadcaster |-------------------------------------------------------------------------- | | This option controls the default broadcaster that will be used by the | framework when an event needs to be broadcast. You may set this to | any of the connections defined in the "connections" array below. | | Supported: "pusher", "redis", "log", "null" | */ 'default' => env('BROADCAST_DRIVER', 'pusher'), /* |-------------------------------------------------------------------------- | Broadcast Connections |-------------------------------------------------------------------------- | | Here you may define all of the broadcast connections that will be used | to broadcast events to other systems or over websockets. Samples of | each available type of connection are provided inside this array. | */ 'connections' => [ 'pusher' => [ 'driver' => 'pusher', 'key' => env('PUSHER_APP_KEY'), 'secret' => env('PUSHER_APP_SECRET'), 'app_id' => env('PUSHER_APP_ID'), 'options' => [ 'cluster' => 'ap2', 'encrypted' => true ], ], 'redis' => [ 'driver' => 'redis', 'connection' => 'default', ], 'log' => [ 'driver' => 'log', ], 'null' => [ 'driver' => 'null', ], ], ];

As you can see, we've changed the default broadcast driver to Pusher. We've also added cluster and encrypted configuration options that you should have got from the Pusher account in the first place.

Also, it's fetching values from environment variables. So let's make sure that we do set the following variables in the .env file properly.

BROADCAST_DRIVER=pusher PUSHER_APP_ID={YOUR_APP_ID} PUSHER_APP_KEY={YOUR_APP_KEY} PUSHER_APP_SECRET={YOUR_APP_SECRET}

Next, I had to make a few changes in a couple of core Laravel files in order to make it compatible with the latest Pusher SDK. Of course, I don't recommend making any changes in the core framework, but I'll just highlight what needs to be done.

Go ahead and open the vendor/laravel/framework/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php file. Just replace the snippet use Pusher; with use Pusher\Pusher;.

Next, let's open the vendor/laravel/framework/src/Illuminate/Broadcasting/BroadcastManager.php file and make a similar change in the following snippet.

return new PusherBroadcaster( new \Pusher\Pusher($config['key'], $config['secret'], $config['app_id'], Arr::get($config, 'options', [])) );

Finally, let's enable the broadcast service in config/app.php by removing the comment in the following line.

App\Providers\BroadcastServiceProvider::class,

So far, we've installed server-specific libraries. In the next section, we'll go through client libraries that need to be installed as well.

Pusher and Laravel Echo Libraries—Installation and Configuration

In broadcasting, the responsibility of the client side is to subscribe to channels and listen for desired events. Under the hood, it accomplishes it by opening a new connection to the web-socket server.

Luckily, we don't have to implement any complex JavaScript stuff to achieve it as Laravel already provides a useful client library, Laravel Echo, that helps us deal with sockets on the client side. Also, it supports the Pusher service that we're going to use in this article.

You can install Laravel Echo using the NPM package manager. Of course, you need to install node and npm in the first place if you don't have them already. The rest is pretty simple, as shown in the following snippet.

$npm install laravel-echo

What we're interested in is the node_modules/laravel-echo/dist/echo.js file that you should copy to public/echo.js.

Yes, I understand, it's a bit of overkill to just get a single JavaScript file. If you don't want to go through this exercise, you can download the echo.js file from my GitHub.

And with that, we're done with our client libraries setup.

Back-End File Setup

Recall that we were talking about setting up an application that allows users of our application to send messages to each other. On the other hand, we'll send broadcast notifications to users that are logged in when they receive a new message from other users.

In this section, we'll create the files that are required in order to implement the use-case that we're looking for.

To start with, let's create the Message model that holds messages sent by users to each other.

$php artisan make:model Message --migration

We also need to add a few fields like to, from and message to our messages table. So let's change the migration file before running the migrate command.

<?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateMessagesTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('messages', function (Blueprint $table) { $table->increments('id'); $table->integer('from', FALSE, TRUE); $table->integer('to', FALSE, TRUE); $table->text('message'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('messages'); } }

Now, let's run the migrate command that creates the messages table in the database.

$php artisan migrate

Whenever you want to raise a custom event in Laravel, you should create a class for that event. Based on the type of event, Laravel reacts accordingly and takes the necessary actions.

If the event is a normal event, Laravel calls the associated listener classes. On the other hand, if the event is of broadcast type, Laravel sends that event to the web-socket server that's configured in the config/broadcasting.php file.

As we're using the Pusher service in our example, Laravel will send events to the Pusher server.

Let's use the following artisan command to create a custom event class—NewMessageNotification.

$php artisan make:event NewMessageNotification

That should create the app/Events/NewMessageNotification.php class. Let's replace the contents of that file with the following.

<?php namespace App\Events; use Illuminate\Broadcasting\Channel; use Illuminate\Queue\SerializesModels; use Illuminate\Broadcasting\PrivateChannel; use Illuminate\Broadcasting\PresenceChannel; use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow; use App\Message; class NewMessageNotification implements ShouldBroadcastNow { use SerializesModels; public $message; /** * Create a new event instance. * * @return void */ public function __construct(Message $message) { $this->message = $message; } /** * Get the channels the event should broadcast on. * * @return Channel|array */ public function broadcastOn() { return new PrivateChannel('user.'.$this->message->to); } }

The important thing to note is that the NewMessageNotification class implements the ShouldBroadcastNow interface. Thus, when we raise an event, Laravel knows that this event should be broadcast.

In fact, you could also implement the ShouldBroadcast interface, and Laravel adds an event into the event queue. It'll be processed by the event queue worker when it gets a chance to do so. In our case, we want to broadcast it right away, and that's why we've used the ShouldBroadcastNow interface.

In our case, we want to display a message the user has received, and thus we've passed the Message model in the constructor argument. In this way, the data will be passed along with the event.

Next, there is the broadcastOn method that defines the name of the channel on which the event will be broadcast. In our case, we've used the private channel as we want to restrict the event broadcast to logged-in users.

The $this->message->to variable refers to the ID of the user to which the event will be broadcast. Thus, it effectively makes the channel name like user.{USER_ID}.

In the case of private channels, the client must authenticate itself before establishing a connection with the web-socket server. It makes sure that events that are broadcast on private channels are sent to authenticated clients only. In our case, it means that only logged-in users will be able to subscribe to our channel user.{USER_ID}.

If you're using the Laravel Echo client library for channel subscription, you're in luck! It automatically takes care of the authentication part, and you just need to define the channel routes.

Let's go ahead and add a route for our private channel in the routes/channels.php file.

<?php /* |-------------------------------------------------------------------------- | Broadcast Channels |-------------------------------------------------------------------------- | | Here you may register all of the event broadcasting channels that your | application supports. The given channel authorization callbacks are | used to check if an authenticated user can listen to the channel. | */ Broadcast::channel('App.User.{id}', function ($user, $id) { return (int) $user->id === (int) $id; }); Broadcast::channel('user.{toUserId}', function ($user, $toUserId) { return $user->id == $toUserId; });

As you can see, we've defined the user.{toUserId} route for our private channel.

The second argument of the channel method should be a closure function. Laravel automatically passes the currently logged-in user as the first argument of the closure function, and the second argument is usually fetched from the channel name.

When the client tries to subscribe to the private channel user.{USER_ID}, the Laravel Echo library does the necessary authentication in the background using the XMLHttpRequest object, or more commonly known as XHR.

So far, we've finished with the setup, so let's go ahead and test it.

Front-End File Setup

In this section, we'll create the files that are required to test our use-case.

Let's go ahead and create a controller file at app/Http/Controllers/MessageController.php with the following contents.

<?php namespace App\Http\Controllers; use App\Http\Controllers\Controller; use App\Message; use App\Events\NewMessageNotification; use Illuminate\Support\Facades\Auth; class MessageController extends Controller { public function __construct() { $this->middleware('auth'); } public function index() { $user_id = Auth::user()->id; $data = array('user_id' => $user_id); return view('broadcast', $data); } public function send() { // ... // message is being sent $message = new Message; $message->setAttribute('from', 1); $message->setAttribute('to', 2); $message->setAttribute('message', 'Demo message from user 1 to user 2'); $message->save(); // want to broadcast NewMessageNotification event event(new NewMessageNotification($message)); // ... } }

In the index method, we're using the broadcast view, so let's create the resources/views/broadcast.blade.php view file as well.

<!DOCTYPE html> <html lang="{{ app()->getLocale() }}"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- CSRF Token --> <meta name="csrf-token" content="{{ csrf_token() }}"> <title>Test</title> <!-- Styles --> <link href="{{ asset('css/app.css') }}" rel="stylesheet"> </head> <body> <div id="app"> <nav class="navbar navbar-default navbar-static-top"> <div class="container"> <div class="navbar-header"> <!-- Collapsed Hamburger --> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#app-navbar-collapse"> <span class="sr-only">Toggle Navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <!-- Branding Image --> <a class="navbar-brand123" href="{{ url('/') }}"> Test </a> </div> <div class="collapse navbar-collapse" id="app-navbar-collapse"> <!-- Left Side Of Navbar --> <ul class="nav navbar-nav"> &nbsp; </ul> <!-- Right Side Of Navbar --> <ul class="nav navbar-nav navbar-right"> <!-- Authentication Links --> @if (Auth::guest()) <li><a href="{{ route('login') }}">Login</a></li> <li><a href="{{ route('register') }}">Register</a></li> @else <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"> {{ Auth::user()->name }} <span class="caret"></span> </a> <ul class="dropdown-menu" role="menu"> <li> <a href="{{ route('logout') }}" onclick="event.preventDefault(); document.getElementById('logout-form').submit();"> Logout </a> <form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;"> {{ csrf_field() }} </form> </li> </ul> </li> @endif </ul> </div> </div> </nav> <div class="content"> <div class="m-b-md"> New notification will be alerted realtime! </div> </div> </div> <!-- receive notifications --> <script src="{{ asset('js/echo.js') }}"></script> <script src="https://js.pusher.com/4.1/pusher.min.js"></script> <script> Pusher.logToConsole = true; window.Echo = new Echo({ broadcaster: 'pusher', key: 'c91c1b7e8c6ece46053b', cluster: 'ap2', encrypted: true, logToConsole: true }); Echo.private('user.{{ $user_id }}') .listen('NewMessageNotification', (e) => { alert(e.message.message); }); </script> <!-- receive notifications --> </body> </html>

And, of course, we need to add routes as well in the routes/web.php file.

Route::get('message/index', 'MessageController@index'); Route::get('message/send', 'MessageController@send');

In the constructor method of the controller class, you can see that we've used the auth middleware to make sure that controller methods are only accessed by logged-in users.

Next, there's the index method that renders the broadcast view. Let's pull in the most important code in the view file.

<!-- receive notifications --> <script src="{{ asset('js/echo.js') }}"></script> <script src="https://js.pusher.com/4.1/pusher.min.js"></script> <script> Pusher.logToConsole = true; window.Echo = new Echo({ broadcaster: 'pusher', key: 'c91c1b7e8c6ece46053b', cluster: 'ap2', encrypted: true, logToConsole: true }); Echo.private('user.{{ $user_id }}') .listen('NewMessageNotification', (e) => { alert(e.message.message); }); </script> <!-- receive notifications -->

Firstly, we load the necessary client libraries, Laravel Echo and Pusher, allowing us to open the web-socket connection to the Pusher web-socket server.

Next, we create the instance of Echo by providing Pusher as our broadcast adapter and other necessary Pusher-related information.

Moving further, we use the private method of Echo to subscribe to the private channel user.{USER_ID}. As we discussed earlier, the client must authenticate itself before subscribing to the private channel. Thus the Echo object performs the necessary authentication by sending the XHR in the background with necessary parameters. Finally, Laravel tries to find the user.{USER_ID} route, and it should match the route that we've defined in the routes/channels.php file.

If everything goes fine, you should have a web-socket connection open with the Pusher web-socket server, and it's listing events on the user.{USER_ID} channel! From now on, we'll be able to receive all incoming events on this channel.

In our case, we want to listen for the NewMessageNotification event and thus we've used the listen method of the Echo object to achieve it. To keep things simple, we'll just alert the message that we've received from the Pusher server.

So that was the setup for receiving events from the web-sockets server. Next, we'll go through the send method in the controller file that raises the broadcast event.

Let's quickly pull in the code of the send method.

public function send() { // ... // message is being sent $message = new Message; $message->setAttribute('from', 1); $message->setAttribute('to', 2); $message->setAttribute('message', 'Demo message from user 1 to user 2'); $message->save(); // want to broadcast NewMessageNotification event event(new NewMessageNotification($message)); // ... }

In our case, we're going to notify logged-in users when they receive a new message. So we've tried to mimic that behavior in the send method.

Next, we've used the event helper function to raise the NewMessageNotification event. Since the NewMessageNotification event is of ShouldBroadcastNow type, Laravel loads the default broadcast configuration from the config/broadcasting.php file. Finally, it broadcasts the NewMessageNotification event to the configured web-socket server on the user.{USER_ID} channel.

In our case, the event will be broadcast to the Pusher web-socket server on the user.{USER_ID} channel. If the ID of the recipient user is 1, the event will be broadcast over the user.1 channel.

As we discussed earlier, we already have a setup that listens to events on this channel, so it should be able to receive this event, and the alert box is displayed to the user!

Let's go ahead and walk through how you are supposed to test the use-case that we've built so far.

Open the URL http://your-laravel-site-domain/message/index in your browser. If you're not logged in yet, you'll be redirected to the login screen. Once you're logged in, you should see the broadcast view that we defined earlier—nothing fancy yet.

In fact, Laravel has done a quite a bit of work in the background already for you. As we've enabled the Pusher.logToConsole setting provided by the Pusher client library, it logs everything in the browser console for debugging purposes. Let's see what's being logged to the console when you access the http://your-laravel-site-domain/message/index page.

Pusher : State changed : initialized -> connecting Pusher : Connecting : {"transport":"ws","url":"wss://ws-ap2.pusher.com:443/app/c91c1b7e8c6ece46053b?protocol=7&client=js&version=4.1.0&flash=false"} Pusher : Connecting : {"transport":"xhr_streaming","url":"https://sockjs-ap2.pusher.com:443/pusher/app/c91c1b7e8c6ece46053b?protocol=7&client=js&version=4.1.0"} Pusher : State changed : connecting -> connected with new socket ID 1386.68660 Pusher : Event sent : {"event":"pusher:subscribe","data":{"auth":"c91c1b7e8c6ece46053b:cd8b924580e2cbbd2977fd4ef0d41f1846eb358e9b7c327d89ff6bdc2de9082d","channel":"private-user.2"}} Pusher : Event recd : {"event":"pusher_internal:subscription_succeeded","data":{},"channel":"private-user.2"} Pusher : No callbacks on private-user.2 for pusher:subscription_succeeded

It has opened the web-socket connection with the Pusher web-socket server and subscribed itself to listen to events on the private channel. Of course, you could have a different channel name in your case based on the ID of the user that you're logged in with. Now, let's keep this page open as we move to test the send method.

Next, let's open the http://your-laravel-site-domain/message/send URL in the other tab or in a different browser. If you're going to use a different browser, you need to log in to be able to access that page.

As soon as you open the http://your-laravel-site-domain/message/send page, you should be able to see an alert message in the other tab at http://your-laravel-site-domain/message/index.

Let's navigate to the console to see what has just happened.

Pusher : Event recd : {"event":"App\\Events\\NewMessageNotification","data":{"message":{"id":57,"from":1,"to":2,"message":"Demo message from user 1 to user 2","created_at":"2018-01-13 07:10:10","updated_at":"2018-01-13 07:10:10"}},"channel":"private-user.2"}

As you can see, it tells you that you've just received the App\Events\NewMessageNotification event from the Pusher web-socket server on the private-user.2 channel.

In fact, you can see what's happening out there at the Pusher end as well. Go to your Pusher account and navigate to your application. Under the Debug Console, you should be able to see messages being logged.

And that brings us to the end of this article! Hopefully, it wasn't too much in a single go as I've tried to simplify things to the best of my knowledge.

Conclusion

Today, we went through one of the least discussed features of Laravel—broadcasting. It allows you to send real-time notifications using web sockets. Throughout the course of this article, we built a real-world example that demonstrated the aforementioned concept.

Yes I know, it's a lot of stuff to digest in a single article, so feel free to use the comment feed below should you find yourself in trouble during implementation.

Categories: Web Design

Getting Started With Redux: Why Redux?

Fri, 05/04/2018 - 06:15

When you're learning React, you will almost always hear people say how great Redux is and that you should give it a try. The React ecosystem is growing at a swift pace, and there are so many libraries that you can hook up with React, such as flow, redux, middlewares, mobx, etc. 

Learning React is easy, but getting used to the entire React ecosystem takes time. This tutorial is an introduction to one of the integral components of the React ecosystem—Redux.

Basic Non-Redux Terminology

Here are some of the commonly used terminologies that you may not be familiar with, but they are not specific to Redux per se. You can skim through this section and come back here when/if something doesn't make sense.  

Pure Function

A pure function is just a normal function with two additional constraints that it has to satisfy: 

  1. Given a set of inputs, the function should always return the same output. 
  2. It produces no side effects.

For instance, here is a pure function that returns the sum of two numbers.

/* Pure add function */ const add = (x,y) => { return x+y; } console.log(add(2,3)) //5

Pure functions give a predictable output and are deterministic. A function becomes impure when it performs anything other than calculating its return value. 

For instance, the add function below uses a global state to calculate its output. In addition, the function also logs the value to the console, which is considered to be a side effect. 

const y = 10; const impureAdd = (x) => { console.log(`The inputs are ${x} and ${y}`); return x+y; } Observable Side Effects

"Observable side effects" is a fancy term for interactions made by a function with the outside world. If a function tries to write a value into a variable that exists outside the function or tries to call an external method, then you can safely call these things side effects. 

However, if a pure function calls another pure function, then the function can be treated as pure. Here are some of the common side effects:

  • making API calls
  • logging to console or printing data
  • mutating data
  • DOM manipulation
  • retrieving the current time
Container and Presentational Components

Splitting the component architecture into two is useful while working with React applications. You can broadly classify them into two categories: container components and presentational components. They are also popularly known as smart and dumb components. 

The container component is concerned with how things work, whereas presentational components are concerned with how things look. To understand the concepts better, I've covered that in another tutorial: Container vs. Presentational Components in React.

Mutable vs. Immutable Objects

A mutable object can be defined as follows:

mutable object is an object whose state can be modified after it is created.

Immutability is the exact opposite—an immutable object is an object whose state cannot be modified after it is created. In JavaScript, strings and numbers are immutable, but objects and arrays are not. The example demonstrates the difference better. 

/*Strings and numbers are immutable */ let a = 10; let b = a; b = 3; console.log(`a = ${a} and b = ${b} `); //a = 10 and b = 3 /* But objects and arrays are not */ /*Let's start with objects */ let user = { name: "Bob", age: 22, job: "None" } active_user = user; active_user.name = "Tim"; //Both the objects have the same value console.log(active_user); // {"name":"Tim","age":22,"job":"None"} console.log(user); // {"name":"Tim","age":22,"job":"None"} /* Now for arrays */ let usersId = [1,2,3,4,5] let usersIdDup = usersId; usersIdDup.pop(); console.log(usersIdDup); //[1,2,3,4] console.log(usersId); //[1,2,3,4]

To make objects immutable, use the Object.assign method to create a new method or the all new spread operator.

let user = { name: "Bob", age: 22, job: "None" } active_user = Object.assign({}, user, {name:"Tim"}) console.log(user); //{"name":"Bob","age":22,"job":"None"} console.log(active_user); //{"name":"Tim","age":22,"job":"None"} What Is Redux?

The official page defines Redux as follows:

Redux is a predictable state container for JavaScript applications. 

Although that accurately describes Redux, it's easy to get lost when you see the bigger picture of Redux for the first time. It has so many moving pieces that you need to fit together. But once you do, I promise you, you'll start loving Redux. 

Redux is a state management library that you can hook up with any JavaScript library, and not just React. However, it works very well with React because of React's functional nature. To understand this better, let's have a look at the state.

As you can see, a component's state determines what gets rendered and how it behaves. The application has an initial state, and any user interaction triggers an action that updates the state. When the state is updated, the page is rerendered.

With React, each component has a local state that is accessible from within the component, or you can pass them down as props to child components. We usually use the state to store:

  1. UI state and transitionary data. This includes a list of UI elements for navigation menu or form inputs in a controlled component.
  2. Application state such as data fetched from a server, the login state of the user, etc.

Storing application data in a component's state is okay when you have a basic React application with a few components. 

Component hierarchy of a basic application

However, most real-life apps will have lots more features and components. When the number of levels in the component hierarchy increases, managing the state becomes problematic. 

Sketch of a medium-sized applicationWhy Should You Use Redux?

Here is a very probable scenario that you might come across while working with React.

  1. You are building a medium-sized application, and you have your components neatly split into smart and dumb components. 
  2. The smart components handle the state and then pass them down to the dumb components. They take care of making API calls, fetching the data from the data source, processing the data, and then setting the state. The dumb components receive the props and return the UI representation. 
  3. When you're about to write a new component, it's not always clear where to place the state. You could let the state be part of a container that's an immediate parent of the presentational component. Better yet, you could move the state higher up in the hierarchy so that the state is accessible to multiple presentational components.
  4. When the app grows, you see that the state is scattered all over the place. When a component needs to access the state that it doesn't immediately have access to, you will try to lift the state up to the closest component ancestor. 
  5. After constant refactoring and cleaning up, you end up with most of the state holding places at the top of the component hierarchy. 
  6. Finally, you decide that it's a good idea to let a component at the top handle the state globally and then pass everything down. Every other component can subscribe to the props that they need and ignore the rest.

This is what I've personally experienced with React, and lots of other developers will agree. React is a view library, and it's not React's job to specifically manage state. What we are looking for is the Separation of Concerns principle. 

Redux helps you to separate the application state from React. Redux creates a global store that resides at the top level of your application and feeds the state to all other components. Unlike Flux, Redux doesn't have multiple store objects. The entire state of the application is within that store object, and you could potentially swap the view layer with another library with the store intact.

The components re-render every time the store is updated, with very little impact on performance. That's good news, and this brings tons of benefits along with it. You can treat all your React components as dumb, and React can just focus on the view side of things.

Now that we know why Redux is useful, let's dive into the Redux architecture.

The Redux Architecture

When you're learning Redux, there are a few core concepts that you need to get used to. The image below describes the Redux architecture and how everything is connected together. 

Redux in a nutshell

If you're used to Flux, some of the elements might look familiar. If not, that's okay too because we're going to cover everything from the base. First, make sure that you have redux installed:

npm install redux

Use create-react-app or your favorite webpack configuration to set up the development server. Since Redux is an independent state management, we're not going to plug in React yet. So remove the contents of index.js, and we'll play around with Redux for the rest of this tutorial.

Store

The store is one big JavaScript object that has tons of key-value pairs that represent the current state of the application. Unlike the state object in React that is sprinkled across different components, we have only one store. The store provides the application state, and every time the state updates, the view rerenders. 

However, you can never mutate or change the store. Instead, you create new versions of the store. 

(previousState, action) => newState

Because of this, you can do time travel through all the states from the time the app was booted on your browser.

The store has three methods to communicate with the rest of the architecture. They are:

  • Store.getState()—To access the current state tree of your application. 
  • Store.dispatch(action)—To trigger a state change based on an action. More about actions below.
  • Store.subscribe(listener)—To listen to any change in the state. It will be called every time an action is dispatched.

Let's create a store. Redux has a createStore method to create a new store. You need to pass it a reducer, although we don't know what that is. So I will just create a function called reducer. You may optionally specify a second argument that sets the initial state of the store. 

src/index.jsimport { createStore } from "redux"; // This is the reducer const reducer = () => { /*Something goes here */ } //initialState is optional. //For this demo, I am using a counter, but usually state is an object const initialState = 0 const store = createStore(reducer, initialState);

Now we're going to listen to any changes in the store, and then console.log() the current state of the store.

store.subscribe( () => { console.log("State has changed" + store.getState()); })

So how do we update the store? Redux has something called actions that make this happen.

Action/Action Creators

Actions are also plain JavaScript objects that send information from your application to the store. If you have a very simple counter with an increment button, pressing it will result in an action being triggered that looks like this:

{ type: "INCREMENT", payload: 1 }

They are the only source of information to the store. The state of the store changes only in response to an action. Each action should have a type property that describes what the action object intends to do. Other than that, the structure of the action is completely up to you. However, keep your action small because an action represents the minimum amount of information required to transform the application state. 

For instance, in the example above, the type property is set to "INCREMENT", and an additional payload property is included. You could rename the payload property to something more meaningful or, in our case, omit it entirely.  You can dispatch an action to the store like this.

store.dispatch({type: "INCREMENT", payload: 1});

While coding Redux, you won't normally use actions directly. Instead, you will be calling functions that return actions, and these functions are popularly known as action creators. Here is the action creator for the increment action that we discussed earlier.

const incrementCount = (count) => { return { type: "INCREMENT", payload: count } }

So, to update the state of the counter, you will need to dispatch the incrementCount action like this:

store.dispatch(incrementCount(1)); store.dispatch(incrementCount(1)); store.dispatch(incrementCount(1));

If you head to the browser console, you will see that it's working, partially. We get undefined because we haven't yet defined the reducer.

So now we have covered actions and the store. However, we need a mechanism to convert the information provided by the action and transform the state of the store. Reducers serve this purpose.

Reducers

An action describes the problem, and the reducer is responsible for solving the problem. In the earlier example, the incrementCount method returned an action that supplied information about the type of change that we wanted to make to the state. The reducer uses this information to actually update the state. There's a big point highlighted in the docs that you should always remember while using Redux:

Given the same arguments, a Reducer should calculate the next state and return it. No surprises. No side effects. No API calls. No mutations. Just a calculation.

What this means is that a reducer should be a pure function. Given a set of inputs, it should always return the same output. Beyond that, it shouldn't do anything more. Also, a reducer is not the place for side effects such as making AJAX calls or fetching data from the API. 

Let's fill in the reducer for our counter.

// This is the reducer const reducer = (state = initialState, action) => { switch (action.type) { case "INCREMENT": return state + action.payload default: return state } }

The reducer accepts two arguments—state and action—and it returns a new state.

(previousState, action) => newState

The state accepts a default value, the initialState, which will be used only if the value of the state is undefined. Otherwise, the actual value of the state will be retained. We use the switch statement to select the right action. Refresh the browser, and everything works as expected. 

Let's add a case for DECREMENT, without which the counter is incomplete.

// This is the reducer const reducer = (state = initialState, action) => { switch (action.type) { case "INCREMENT": return state + action.payload case "DECREMENT": return state - action.payload default: return state } }

Here's the action creator.

const decrementCount = (count) => { return { type: "DECREMENT", payload: count } }

Finally, dispatch it to the store.

store.dispatch(incrementCount(4)); //4 store.dispatch(decrementCount(2)); //2

That's it!

Summary

This tutorial was meant to be a starting point for managing state with Redux. We've covered everything essential needed to understand the basic Redux concepts such as the store, actions, and reducers. Towards the end of the tutorial, we also created a working redux demo counter. Although it wasn't much, we learned how all the pieces of the puzzle fit together. 

Over the last couple of years, React has grown in popularity. In fact, we have a number of items in the marketplace that are available for purchase, review, implementation, and so on. If you’re looking for additional resources around React, don’t hesitate to check them out.

In the next tutorial, we will make use of the things we've learned here to create a React application using Redux. Stay tuned until then. Share your thoughts in the comments. 

Categories: Web Design

20 Useful PHP Scripts Available on CodeCanyon

Thu, 05/03/2018 - 12:18

For many, PHP is the lifeblood of web development.

It may be a general-purpose scripting language, but it powers WordPressDrupalMagento, and more; not to mention the thousands of individual PHP scripts available. If you've got a problem that needs an online solution, more than likely, you can solve it by creating a PHP script—or by downloading something already built.

PHP is clearly suited for web development. Take these 20 popular PHP scripts available on Envato Market, for example:

1. Vanguard - Login and User Management

If you run a website of any sort and are looking to introduce some type of login and authentication management, then take a look at Vanguard.

In short, Vanguard is a Laravel-based application that makes it possible to introduce user registration, login, and authentication (through a variety of techniques) to a pre-existing website.

Some of the features it offers include:

  • interactive dashboard
  • unlimited number of user roles
  • powerful admin panel
  • unlimited number of permissions
  • super easy installation using installation wizard
  • user activity log
  • Avatar upload with crop feature
  • built using Twitter Bootstrap
  • active sessions management (see and manage all your active sessions)
  • full Unicode support
  • client-side and server-side form validation
  • fully customizable from settings section
  • complete and detailed documentation
  • fully object-oriented and commented PHP and JavaScript code.
  • localization support—translate the application to any language (English, Serbian and German translations included)
  • with more

If you run a website and are trying to figure out how to introduce memberships without moving to a completely different platform, give Vanguard a try. Perhaps it'll give you exactly what you need.

2. Instagram Auto Post & Scheduler - Nextpost Instagram

Turn your Instagram into an automated marketing powerhouse using Instagram Auto Post & Scheduler - Nextpost Instagram. This online marketing tool allows you to auto-post, schedule, and manage your Instagram accounts from one place.

"With Nextpost, you can post and assess your posts in a single panel and save time managing multiple Instagram accounts."

Features include:

  • extendable
  • proxy support
  • schedule posts
  • easy installation and great UI
  • supports multiple Instagram accounts
  • supports photo, story, video, and albums
  • and much, much more

The list of features included are impressive and include just about anything you would ever want with an Instagram online marketing tool.

Instagram Auto Post & Scheduler - Nextpost Instagram is a must-have for any Instagram marketer.

3. PHP Login & User Management

There's no need to use an entire CMS to handle user logins and have private pages that can only be viewed by logged-in visitors to your website.

This can easily be done by leveraging PHP Login & User Management, a MySQL-powered website PHP login script. You can even change User Levels using the built-in Control Panel when you need different levels of page security.

This script includes:

  • captcha integration
  • profiles
  • social media login support
  • login expiration
  • lost password activation code email
  • welcome and activation emails
  • as well as many control panel features for Admin

With the installation wizard and the HTML5 Twitter Bootstrap design, you'll be up and running with solid PHP Login & User Management in no time.

4. Ultimate Client Manager - CRM - Pro Edition

If you need a CRM for your business, or maybe you want to up your freelance project management, instead of adding another monthly fee to your expenses, why not host your own customer and project management system?

More specifically, the Ultimate Client Manager - CRM - Pro Edition.

UCM Pro really does pack an impressive punch of features. You can:

  • enjoy industry-standard PGP/RSA encrypted fields
  • email support tickets
  • organize your leads, customers, projects, and invoices
  • have your customers log in and see their project status
  • enable subscription billing features to help organize and automate client billing
  • convert invoices into PDF documents
  • make multiple currency and tax rate adjustments
  • have customers and staff upload project files

This is only a fraction of the useful features you'll find. And while this CRM contender is robust enough to challenge many other subscription-based CRMs, it's the little things like being able to change your CRM theme that give the Ultimate Client Manager - CRM - Pro Edition that extra polish.

5. Perfex - Open Source CRM

When it comes to managing customer relationships, there are a wide variety of solutions. Truth be told, it's not a one-size-fits-all solution, which is why it's a good thing to have a number of choices.

And one of those is Perfex.

Since we're all looking for a different set of features as it relates to CRM systems, here are some of the things that Perfex offers its users:

  • Build professional, great-looking estimates and invoices.
  • Powerful support system with the ability to auto-import tickets.
  • Track time spent on tasks and bill your customers. Ability to assign multiple staff members on task and track time per assigned staff member.
  • Add task followers even if the staff member is not a project member. The staff member will be able to track the task progress without accessing the project.
  • Keep track of leads in one place and easily follow their progress. Ability to auto import leads from email, add notes, and create proposals. Organize your leads in stages and change stages easily with drag and drop.
  • Create good-looking proposals for leads or customers and increase sales.
  • Record your company/project expenses and have the ability to bill to your customers and auto-convert to invoices.
  • Know more about your customers with a powerful CRM.
  • And much, much more

You can view features, requirements, and more on the product page.

This particular product is inexpensive, available in the marketplace, and can be installed on any system that supports PHP and MySQL (which is nearly any popular, current host). 

6. PHP Live Chat Pro

Build your own PHP and MySQL chat without monthly fees using PHP Live Chat Pro. This useful PHP script boasts many useful features.

"Live Support Chat. PHP & MySQL based. For any website. No monthly fees."

Features include:

  • easy to install installation wizard
  • conversation history with filters
  • full translation support
  • supports file sharing
  • sound notifications
  • mobile support
  • geolocation
  • and more

From the desktop to mobile applications, this works with any website.

Start chatting it up with PHP Live Chat Pro.

7. Turbo Website Reviewer - In-Depth SEO Analysis Tool

Analyze SEO issues using the Turbo Website Reviewer - In-Depth SEO Analysis Tool and provide white-labeled PDF reports. With over 50 different checks, this tool checks key issues surrounding good SEO.

"Turbo Website Reviewer helps to identify your SEO mistakes and optimize your web page contents for a better search engine ranking."

Features include:

  • user management system
  • full multilingual support
  • powerful admin control
  • fully customizable
  • built-in analytics
  • easy installation
  • and more

With a side-by-side domain comparison, the Turbo Website Reviewer - In-Depth SEO Analysis Tool includes just about anything you would ever want to be included in an SEO analysis tool.

8. Super Store Finder

Customers can easily find your store in style with Super Store Finder.

By fully integrating Google API V3 and using Geo IP to detect the user location, Super Store Finder allows your customers to find your location quickly and easily from their smartphones.

The Twitter Bootstrap powered design—complete with modal popups, tabs, alerts, and more—looks great on the desktop or smartphone. But it's the feature set of this PHP script that really catches your eye:

  • results sorted from nearest to furthest
  • use Google Street View
  • unlimited locations
  • bulk CSV import
  • autofill search field
  • multi-language support
  • users can request to add locations
  • multiple admins
  • add your own map markers
  • and much, much, more

This is a great way to leverage Google Maps into your website for both desktop and mobile users, and includes enough unique features to use Super Store Finder for more than your stereotypical use cases.

9. MailWizz - Email Marketing Application

There's no need to keep monkeying around with your email marketing.

If you're serious about having your own email marketing application, this is a great place to start. In fact, the MailWizz - Email Marketing Application is robust and feature-rich enough for you to become an email service provider for your customers!

Autoresponders? Check.

Restful API and Web Hooks? Double check.

Powerful theming system, customizable list forms, and customer back end? Triple check.

You'll have no problem sending tens of thousands of emails in just an hour, or importing and exporting subscriber lists, reports, and stats; not to mention enjoying IP location services, and best of all, unlimited lists and subscribers.

The MailWhizz - Email Marketing Application includes support for many delivery servers, including SMTP Amazon SES, Directory Pickup, PHP's mail, and Sendmail.

10. Freelance Cockpit

If you're a freelancer, then you know the challenges of managing all of the overhead that comes with actually managing the business (aside from managing solutions for your clients).

Freelance Cockpit aims to help you do exactly that.

The application offers an all-in-one solution for managing projects, tasks, support, messaging, and so much more. Some of the features include:

  • Multi File Upload and File Commenting. On all projects you can upload any kind of files, like a screenshot of the mockup you made for a new web project, and share them with your client.
  • Client Management. Easily manage your clients with all the details you need.
  • Client Portal. Your clients can view the status of their projects and invoices.
  • Invoice Management. Creating and sending invoices was never that easy!
  • Expenses. Track all your expenses.
  • Estimates. Send estimates to your clients.
  • Recurring Invoices. Create recurring invoices.
  • Calendar. Beautiful calendar with optional Google calendar integration.
  • Item Management. Manage your items/products.
  • Reports. A nice chart to view your income and expenses in a given period.
  • User Activity Widget. See who is online.
  • Email Notifications. Get email notifications on new messages, project assignment, etc.
  • User Access Levels. Control the access of your agents to the different modules.
  • Quick Access. Quickly open a project or start/stop the timer using the Quick Access widget.
  • Database backup. Never lose any data again!
  • And more.

If you're a freelancer, or even a small business, and you're looking for an all-in-one solution to help manage the overhead for all things that you're doing related to your business, check out Freelance Cockpit.

11. Coin Table - Cryptocurrency Market CMS

Keep up to date and share the current exchange rate for over 1,000 different cryptocurrencies with the Coin Table - Cryptocurrency Market CMS. Easily manage it within its own admin panel and create multiple authenticated users.

"Coin Table is a Content Management System built for Cryptocurrency Real-time Information."

Customizable pages include:

  • home
  • table
  • currency
  • converter

Features include:

  • supports all the major social networks
  • plug and play custom HTML ads
  • convert to 156 currencies
  • and more

Keep up with Bitcoin and cryptocurrency with Coin Table - Cryptocurrency Market CMS.

12. Premium URL Shortener

If you've used Bit.ly very much—especially if you're using a custom domain—you'll find there's a giant leap between their free and paid service. That makes something like Premium URL Shortener a "no-brainer".

This PHP URL shortener was built with performance in mind, and that's exactly what it does. It comes complete with a powerful dashboard, admin, and geotargeting, and it's fully social-media ready. You'll not only enjoy using Premium URL Shortener, but maybe even take advantage of the new built-in membership system.

13. ContactMe - Responsive AJAX Contact Form - HTML5 PHP

There's hardly anything more useful than a good contact form. Look no further! ContactMe - Responsive AJAX Contact Form - HTML5 PHP is an excellent solution.

"Extremely customizable Contact Form, in a easy and quick way you can create THOUSANDS of different Contact Forms to fit your needs!"

Forms include:

  • general
  • send files
  • hotel contact
  • job application
  • restaurant contact
  • and many more

With over 28 combinations ready to use, you'll be up and running quickly with a good-looking contact form.

Features include:

  • no database required
  • easy to customize
  • add attachments
  • no page reload
  • supports CC
  • and more

ContactMe - Responsive AJAX Contact Form - HTML5 PHP is perfect for every developer's toolkit.

14. PHP Live Support Chat

Set up a live support chat system with PHP Live Support Chat. This PHP and SQL-based solution brings real-time chat to your website.

(Yes, it also includes a high-quality emoticon set.)

On the customer/user side, PHP Live Support Chat offers:

  • a well-designed chat window
  • avatars and emoticons to keep communication clear
  • and mobile support

From the customer support side, you'll benefit from the:

  • chat logs
  • desktop notifications
  • prepared messages
  • and more!

PHP Live Support Chat is easy to install, supports multiple users at once, and has unlimited usage.

15. VTGram - For Instagram Marketing

Ever since Instagram introduced videos, anyone and everyone who uses the service has seen the sponsored posts.

But what if you were able to leverage the platform to market your own product without needing to use the sponsorship features they provide? Or what if you were able to target people, likes, comments, posts, etc., all from within a single application.

Enter VTGram.

Just some of the features include:

  • Auto Post: You can post an image and/or video. The world’s first Instagram video posting tool post from your desktop—PC or Mac.
  • Auto Direct Message: You can send direct messages to your followers easily.
  • Auto Comment: Search and comment all the posts you want in one click.
  • Auto Like: Search and like all the posts you want in one click.
  • Auto Follow: The fastest and most economical way for you if you want to increase following.
  • Auto Unfollow: One reason that you want to unfollow all friends. Tools can also help you.
  • Auto Follow Back: You’re tired of follow back. This feature will help you save time.
  • Search: Search top hashtags and users in the quickest way.
  • Social Login: Supported login via Facebook, Google, and Twitter.

You can purchase, read more, see the requirements, and even test drive the application all from its page in the Envato marketplace.

16. phpDolphin - Social Network Platform

With the popularity of Facebook, many people have found themselves leaving the popular social network for smaller, niche online communities.

With the phpDolphin - Social Network Platform, you can host your very own social network.

Facebook users will find themselves right at home with:

  • likes
  • profile pages
  • news feed
  • groups
  • sharing
  • and much more

As Admin, you'll have full control to manage users, groups, and reports. You can even add phpDolphin plugins to extend your social network's features—Dislike Plugin, anyone?

phpDolphin is very robust, so don't let its Facebook "cloned" design deter you from it.

17. Ninja Media Script - Viral Fun Media Sharing Site

Creating your own media sharing site has never been so easy—or looked this good!

The Ninja Media Script - Viral Fun Media Sharing Site delivers lots of features and solid design.

Built with Laravel 4, Bootstrap 3, Font Awesome 4, and more, this PHP script is easy to install, customizable, and fully responsive.

Users can log in and register with their email address, Facebook, or Google, and then upload images and videos that can then be approved by a site admin or published directly.

Add a logo, use a watermark, choose your layout—you're dealing with a ninja.

Features include:

  • add pages
  • commenting
  • likes
  • NSFW functionality
  • translation ready
  • and more

Any YouTube, Vimeo, Vine, GIF, or JPG could go viral with the Ninja Media Script - Viral Fun Media Sharing Site PHP script.

18. FileGator

Copy, move, rename, edit, delete and upload files online with FileGator.

Without using a database—or Flash—you can run this powerful PHP file manager and Ajax uploader.

Share, zip, and manage multiple files online with your own file manager.

With FileGator's fast and easy-to-use UI, you can:

  • use Google's URL shortener for email links
  • have multiple user and guest accounts
  • search files and folders
  • create archives with zip
  • unzip and decompress files online
  • and much more

Easy to install, easy to use, easy to download FileGator.

19. Stock Manager Advance with Point of Sale Module

You can update product stock, purchases, and sales with an Internet connection and Stock Manager Advance with Point of Sale Module.

Manage multiple warehouses, generate reports, and more.

Features:

  • works well with touch screens
  • print order and bill
  • supports Stripe and PayPal Pro
  • calendar and calculator
  • staff and customer notifications
  • and more

Manage your standard, combo, and digital products with Stock Manager Advance with Point of Sale Module.

20. Rise Project Manager

Project management is one of those areas of running a business that some prefer more than others. If you're a freelancer, it comes with the territory; if you're part of a larger business, then it may be your role.

Regardless, finding the best way to manage said projects can be tough. Perhaps Rise is a viable solution?

Straight from the product page:

Ultimate Project Manager is the best way to manage your projects, clients and team members. You can easily collaborate with your team and monitor your work. It’s easy to use & install.

And it has a ton of features, to boot. Some of the examples include:

  • Projects. Manage all your projects using some amazing tools. Create tasks in projects and assign your team members on the tasks. Create milestones to estimate the timeframe. Upload files by dragging and dropping in projects and discuss with your team. Let your team members comment on tasks and get notifications for important events. See activity logs for projects.
  • Clients. It’s very simple to add your clients in Rise. You’ll get detailed information about contacts, projects, invoices, payments, estimates, tickets and notes of each client. You can allow your clients to use the client portal. Each client will get a separate dashboard to see their projects. Let your clients create tasks for the projects and get feedback instantly.
  • Team members. Assign tasks to your team members and monitor the status easily. You can set different permissions on their access.
  • Invoices. Send invoices to your clients by email with a PDF copy of the invoice. And get paid online via Stripe and PayPal.
  • Estimates. Create estimate request forms according to your needs and let your clients request estimates. Review the estimate requests and submit your estimates to clients.
  • Tickets. Let your clients create support tickets and get notification by web and email. Assign team members to tickets and track the status.
  • Expenses. Track all your expenses and get information about your project cost easily.
  • Event calendar. Create your personal events list and share events with team members.
  • Messaging. Send private messages to team members and clients.

And there's clearly much, much more.

If you find yourself in this role, then I highly recommend checking out what Rise has to offer and see if it fits the bill. In a field that's got a lot of competition, this particular product may hit the right price point.

Conclusion

You can clearly see how versatile PHP is—it can be used for anything from simple solutions to full social networks and project management.

On Envato Tuts+, you'll find all kinds of helpful resources to learn PHP, like PHP tutorialscode eBooks, and video code courses. I particularly enjoy the video code courses. They have beginner PHP courses, like Introduction to WordPress Plugin Development and PHP Fundamentals, or more advanced video courses such as PHP Object Oriented Programming Fundamentals and Go Further With WooCommerce Themes. No matter your learning style, you'll be sure to find helpful PHP code courses.

And if you're curious to know what other PHP scripts are out there, take a peek at what's on offer at Envato Market.

Categories: Web Design

How to Find and Fix Poor Page Load Times With Raygun

Thu, 04/26/2018 - 07:43

In this tutorial, we'll focus on finding and fixing poor page load times with Raygun. But before we do that, let's discuss why slightly longer page load times can be such a big deal.

One of the most important things that you can do to make a good first impression on potential customers or clients visiting your website is improve its loading speed.

Imagine a customer who just heard about your company from a friend. You sell a product online which users can purchase by visiting your website. If different website pages are taking a long time to load and you are not selling that product exclusively, there is a good chance that the customer will abandon your site and go somewhere else.

You did not just miss out on your first sale here, you also missed the opportunity to have a loyal customer who would have purchased more products in the future. 

That's the thing with the Internet—people are just a few clicks away from leaving your website and buying something from your competitors. Faster loading pages can give you an edge over competitors and increase your revenue.

How Can Raygun Help?

Raygun relies on Real User Monitoring Insights (RUM Insights) to improve a website's performance and page load time. The term "Real User Monitoring" is the key here. You could use tools like WebPagetest and Google Page Speed Insights to optimize individual pages, but those results will not be based on real user data. On the other hand, the data provided by Raygun is based on real users who visited your website.

Raygun also presents the information in a more organized manner by telling you things like the average page speed for the website, the most requested pages, and the slowest pages. This way, you can prioritize which page or section of the website needs to be optimized first.

You can also see how fast the website is loading for users in different countries or for users with different browsers. Similarly, you can compare the speed of your website on mobile vs. desktop. 

Another advantage of Raygun is that it will show you how the website is performing for different users. For example, the website may be loading slowly for one of your most valuable clients. In such cases, you would definitely like to know about it and do something to improve their experience before it is too late.

We will learn how to do all that with Raygun in the next few sections of this article.

Integrating Raygun Into Your Website

You need to sign up for an account before integrating Raygun into your website. This account will give you access to all Raygun features for free for 14 days.

Once you have registered successfully, you can click on the Create Application button to create a new application. You can fill out a name for your application on the next screen and then check some boxes to receive notifications about errors and real user monitoring insights.

Now you just have to select your development platform or framework. In this case, we are using JavaScript.

Finally, you will get some code that you have to add on all the pages you want to monitor. Instead of placing the following code in your website, you could also download the production or development version of the library and include it yourself.

<script type="text/javascript"> !function(a,b,c,d,e,f,g,h){a.RaygunObject=e,a[e]=a[e]||function(){ (a[e].o=a[e].o||[]).push(arguments)},f=b.createElement(c),g=b.getElementsByTagName(c)[0], f.async=1,f.src=d,g.parentNode.insertBefore(f,g),h=a.onerror,a.onerror=function(b,c,d,f,g){ h&&h(b,c,d,f,g),g||(g=new Error(b)),a[e].q=a[e].q||[],a[e].q.push({ e:g})}}(window,document,"script","//cdn.raygun.io/raygun4js/raygun.min.js","rg4js"); </script>

Once you have added the above code snippet before the closing </head> tag, you have to place the following snippet just before the closing <body> tag.

<script type="text/javascript"> rg4js('apiKey', 'YOUR_API_KEY'); rg4js('enableCrashReporting', true); rg4js('enablePulse', true); </script>

If you don't add any more code, Raygun will now start collecting anonymous data. This means that you will be able to know how your website is performing for different users, but there will be no way to identify those users.

There is an easy fix for this problem. All you have to do is add the following code in your webpages and Raygun will take care of the rest.

rg4js('setUser', { identifier: 'unique_id', isAnonymous: false, email: 'users_email@domain.com', firstName: 'Firstname', fullName: 'Firstname Lastname' });

You will have to include these three pieces of code in all the pages that you want to track. Once done, the data will start showing up in the dashboard for you to analyze.

Finding Pages With Poor Load Times

The Real User Monitoring section in the Raygun dashboard has a lot of tabs to present the data in different formats. We will briefly go over all these tabs to show you how the information presented in them can be used to find pages with poor load times.

The Live tab will give you an overview of your site's performance in real time. It has different metrics like Health Score to show you how the site is currently performing. You can read more about all these metrics in the documentation for the Live tab on the Raygun website.

It also has a world map to point out the countries of your currently active users. You will also find a list of most recent requests to your website by different users. Here is an image showing the most recent requests to our website.

The performance tab has five useful metrics to give you a quick overview of the website page load times. For example, a median load time of 1.41 seconds means that 50% of your pages load before 1.41 seconds have passed. Similarly, a P90 Load Time of 6.78 seconds tells you that 90% of the time, the website loads before 6.48 seconds.

This should give you a rough idea of the performance of a website and how slow it is for the slowest 10% of users.

The performance tab also has a list of the slowest and most requested pages at the bottom. Knowing the most popular and the slowest pages can be very helpful when you want to prioritize which sections of your website need to be fixed first.

Even though all pages in a website should load as quickly as possible, some of these pages are more important than others. Therefore, you might be interested in finding out the performance of a particular page on a website. You can do so by simply typing the page you are looking for in the input field. This will give you information about the median, average, and P90 load time of a particular page. Here is the data for the home page of our website.

You can use the Sessions tab to see session-related information like the total number of sessions, total number of users, and median session length. The sessions table will give you a quick overview of the last 150 sessions with information like the country, duration, total page views, and the last visited page for a session.

Clicking on the magnifying glass will show you more details of a particular session like the pages the user visited, the load time of those pages, and the browser/device used during the session.

The Users tab will give you an overview of the satisfaction level of different users with your website. This can be very helpful when you want to see how a particular user is interacting with your website and if or why their page load time is more than expected.

There are three other tabs to show information about all the page views in terms of browsers, platforms, and geography. This way you will be able to know if a webpage is loading slowly only on a particular browser or platform. You will also have a rough idea of the distribution of users. For instance, knowing if most of your clients are from a particular country or use a particular browser can be very handy.

Raygun lists the percentage of visitors from a particular continent at the top of the Geo tab. After that, it provides a map with the distribution of load times. Countries with the slowest load times are filled with red, and countries with quick load times are filled with green.

If you are consistently getting poor loading times from a particular country, it might be worth your time to look closely and find out the reason.

Fixing Poor Page Load Times

In the previous section, we learned how to use all the data collected by Raygun to figure out which pages are taking a long time to load or if there are any countries where our page load times are longer than usual.

Now it is time to see how we can use Raygun to discover issues which might be causing a particular page or the whole website to load slower than usual.

Improving poor page load time of a website can be pretty overwhelming, especially if the website is very complicated or if it has a lot of pages. The trouble is in finding what to improve and where to start.

Luckily, Raygun can offer you some general insights to fix your website. You can click on the Insights options under the Real User Monitoring menu, and Raygun will scan your website for any potential issues. You can find a list of all these rules in the official Raygun documentation. Fixing all the listed issues will significantly speed up your website.

Besides following these general guidelines, you might also want to isolate the pages that have been loading slowly. Once you have isolated them, Raygun can show you the time they take to resolve DNS, latency, SSL handshake, etc. This will give you a good idea of the areas where you can make improvements to reduce the page load time. The following image should make it clear.

You can also filter the data in order to get a more accurate picture of the load time for a particular page and various factors affecting it. The above image showed you the average latency for all requests made to the "About Us" page. However, you can click on the Add Filter button at the top and only see the "About Us" loading time graph for a specific country like Italy.

You will also see all the requests made by a specific page at the bottom. Basically, you will be able to see the DNS, latency, SSL, server, and transfer time for every resource loaded for a specific page and see if any of them is the culprit.

Once you find out which resources are taking too long to load, you can start optimizing your pages.

Final Thoughts

As you saw in this tutorial, Raygun can be of great help to organizations looking to improve their page load times. It is super easy to integrate, and after successful integration, the data will simply start showing up in the dashboard without any intervention from your side.

Raygun also has different tabs to organize the collected data so that you can analyze it more easily and efficiently. For example, it can show you load times for different countries, browsers, and platforms. It also has filters that you can use to isolate a particular set of data from the rest and analyze it closely.

If you or your company are looking for an easy-to-integrate tool which can provide great insights about how your real users are interacting with your website, you should definitely give Raygun a try. You don't have anything to lose since it is free for the first 14 days!

And while you're here, check out some of our other tutorials on Raygun!

Categories: Web Design

Notifications in Laravel

Mon, 04/23/2018 - 05:00

In this article, we're going to explore the notification system in the Laravel web framework. The notification system in Laravel allows you to send notifications to users over different channels. Today, we'll discuss how you can send notifications over the mail channel.

Basics of Notifications

During application development, you often need to notify users about different state changes. It could be either sending email notifications when the order status is changed or sending an SMS about their login activity for security purposes. In particular, we're talking about messages that are short and just provide insight into the state changes.

Laravel already provides a built-in feature that helps us achieve something similar—notifications. In fact, it makes sending notification messages to users a breeze and a fun experience!

The beauty of that approach is that it allows you to choose from different channels notifications will be sent on. Let's quickly go through the different notification channels supported by Laravel.

  • Mail: The notifications will be sent in the form of email to users.
  • SMS: As the name suggests, users will receive SMS notifications on their phone.
  • Slack: In this case, the notifications will be sent on Slack channels.
  • Database: This option allows you to store notifications in a database should you wish to build a custom UI to display it.

Among different notification channels, we'll use the mail channel in our example use-case that we're going to develop over the course of this tutorial.

In fact, it'll be a pretty simple use-case that allows users of our application to send messages to each user. When users receive a new message in their inbox, we'll notify them about this event by sending an email to them. Of course, we'll do that by using the notification feature of Laravel!

Create a Custom Notification Class

As we discussed earlier, we are going to set up an application that allows users of our application to send messages to each other. On the other hand, we'll notify users when they receive a new message from other users via email.

In this section, we'll create necessary files that are required in order to implement the use-case that we're looking for.

To start with, let's create the Message model that holds messages sent by users to each other.

$php artisan make:model Message --migration

We also need to add a few fields like to, from and message to the messages table. So let's change the migration file before running the migrate command.

<?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateMessagesTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('messages', function (Blueprint $table) { $table->increments('id'); $table->integer('from', FALSE, TRUE); $table->integer('to', FALSE, TRUE); $table->text('message'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('messages'); } }

Now, let's run the migrate command that creates the messages table in the database.

$php artisan migrate

That should create the messages table in the database.

Also, make sure that you have enabled the default Laravel authentication system in the first place so that features like registration and login work out of the box. If you're not sure how to do that, the Laravel documentation provides a quick insight into that.

Since each notification in Laravel is represented by a separate class, we need to create a custom notification class that will be used to notify users. Let's use the following artisan command to create a custom notification class—NewMessage.

$php artisan make:notification NewMessage

That should create the app/Notifications/NewMessage.php class, so let's replace the contents of that file with the following contents.

<?php // app/Notifications/NewMessage.php namespace App\Notifications; use Illuminate\Bus\Queueable; use Illuminate\Notifications\Notification; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; use App\User; class NewMessage extends Notification { use Queueable; public $fromUser; /** * Create a new notification instance. * * @return void */ public function __construct(User $user) { $this->fromUser = $user; } /** * Get the notification's delivery channels. * * @param mixed $notifiable * @return array */ public function via($notifiable) { return ['mail']; } /** * Get the mail representation of the notification. * * @param mixed $notifiable * @return \Illuminate\Notifications\Messages\MailMessage */ public function toMail($notifiable) { $subject = sprintf('%s: You\'ve got a new message from %s!', config('app.name'), $this->fromUser->name); $greeting = sprintf('Hello %s!', $notifiable->name); return (new MailMessage) ->subject($subject) ->greeting($greeting) ->salutation('Yours Faithfully') ->line('The introduction to the notification.') ->action('Notification Action', url('/')) ->line('Thank you for using our application!'); } /** * Get the array representation of the notification. * * @param mixed $notifiable * @return array */ public function toArray($notifiable) { return [ // ]; } }

As we're going to use the mail channel to send notifications to users, the via method is configured accordingly. So this is the method that allows you to configure the channel type of a notification.

Next, there's the toMail method that allows you to configure various email parameters. In fact, the toMail method should return the instance of \Illuminate\Notifications\Messages\MailMessage, and that class provides useful methods that allow you to configure email parameters.

Among various methods, the line method allows you to add a single line in a message. On the other hand, there's the action method that allows you to add a call-to-action button in a message.

In this way, you could format a message that will be sent to users. So that's how you're supposed to configure the notification class while you're using the mail channel to send notifications.

At the end, you need to make sure that you implement the necessary methods according to the channel type configured in the via method. For example, if you're using the database channel that stores notifications in a database, you don't need to configure the toMail method; instead, you should implement the toArray method, which formats the data that needs to be stored in a database.

How to Send Notifications

In the previous section, we created a notification class that's ready to send notifications. In this section, we'll create files that demonstrate how you could actually send notifications using the NewMessage notification class.

Let's create a controller file at app/Http/Controllers/NotificationController.php with the following contents.

<?php namespace App\Http\Controllers; use App\Http\Controllers\Controller; use App\Message; use App\User; use App\Notifications\NewMessage; use Illuminate\Support\Facades\Notification; class NotificationController extends Controller { public function __construct() { $this->middleware('auth'); } public function index() { // user 2 sends a message to user 1 $message = new Message; $message->setAttribute('from', 2); $message->setAttribute('to', 1); $message->setAttribute('message', 'Demo message from user 2 to user 1.'); $message->save(); $fromUser = User::find(2); $toUser = User::find(1); // send notification using the "user" model, when the user receives new message $toUser->notify(new NewMessage($fromUser)); // send notification using the "Notification" facade Notification::send($toUser, new NewMessage($fromUser)); } }

Of course, you need to add an associated route in the routes/web.php file.

Route::get('notify/index', 'NotificationController@index');

There are two ways Laravel allows you to send notifications: by using either the notifiable entity or the Notification facade.

If the entity model class utilizes the Illuminate\Notifications\Notifiable trait, then you could call the notify method on that model. The App\User class implements the Notifiable trait and thus it becomes the notifiable entity. On the other hand, you could also use the Illuminate\Support\Facades\Notification Facade to send notifications to users.

Let's go through the index method of the controller.

In our case, we're going to notify users when they receive a new message. So we've tried to mimic that behavior in the index method in the first place.

Next, we've notified the recipient user about a new message using the notify method on the $toUser object, as it's the notifiable entity.

$toUser->notify(new NewMessage($fromUser));

You may have noticed that we also pass the $fromUser object in the first argument of the __construct method, since we want to include the from username in a message.

On the other hand, if you want to mimic it using the Notification facade, it's pretty easy to do so using the following snippet.

Notification::send($toUser, new NewMessage($fromUser));

As you can see, we've used the send method of the Notification facade to send a notification to a user.

Go ahead and open the URL http://your-laravel-site-domain/notify/index in your browser. If you're not logged in yet, you'll be redirected to the login screen. Once you're logged in, you should receive a notification email at the email address that's attached with the user 1.

You may be wondering how the notification system detects the to address when we haven't configured it anywhere yet. In that case, the notification system tries to find the email property in the notifiable object. And the App\User object class already has that property as we're using the default Laravel authentication system.

However, if you would like to override this behavior and you want to use a different property other than email, you just need to define the following method in your notification class.

public function routeNotificationForMail() { return $this->email_address; }

Now, the notification system should look for the email_address property instead of the email property to fetch the to address.

And that's how to use the notification system in Laravel. That brings us to the end of this article as well!

Conclusion

What we've gone through today is one of the useful, yet least discussed, features in Laravel—notifications. It allows you to send notifications to users over different channels.

After a quick introduction, we implemented a real-world example that demonstrated how to send notifications over the mail channel. In fact, it's really handy in the case of sending short messages about state changes in your application.

For those of you who are either just getting started with Laravel or looking to expand your knowledge, site, or application with extensions, we have a variety of things you can study in Envato Market.

Should you have any queries or suggestions, don't hesitate to post them using the feed below!

Categories: Web Design

Introduction to the Stimulus Framework

Fri, 04/20/2018 - 05:15

There are lots of JavaScript frameworks out there. Sometimes I even start to think that I'm the only one who has not yet created a framework. Some solutions, like Angular, are big and complex, whereas some, like Backbone (which is more a library than a framework), are quite simple and only provide a handful of tools to speed up the development process.

In today's article I would like to present you a brand new framework called Stimulus. It was created by a Basecamp team led by David Heinemeier Hansson, a popular developer who was the father of Ruby on Rails.

Stimulus is a small framework that was never intended to grow into something big. It has its very own philosophy and attitude towards front-end development, which some programmers might like or dislike. Stimulus is young, but version 1 has already been released so it should be safe to use in production. I've played with this framework quite a bit and really liked its simplicity and elegance. Hopefully, you will enjoy it too!

In this post we'll discuss the basics of Stimulus while creating a single-page application with asynchronous data loading, events, state persistence, and other common things.

The source code can be found on GitHub.

Introduction to Stimulus

Stimulus was created by developers at Basecamp. Instead of creating single-page JavaScript applications, they decided to choose a majestic monolith powered by Turbolinks and some JavaScript. This JavaScript code evolved into a small and modest framework which does not require you to spend hours and hours learning all its concepts and caveats.

Stimulus is mostly meant to attach itself to existing DOM elements and work with them in some way. It is possible, however, to dynamically render the contents as well. All in all, this framework is quite different from other popular solutions as, for example, it persists state in HTML, not in JavaScript objects. Some developers may find it inconvenient, but do give Stimulus a chance, as it really may surprise you.

The framework has only three main concepts that you should remember, which are:

  • Controllers: JS classes with some methods and callbacks that attach themselves to the DOM. The attachment happens when a data-controller "magic" attribute appears on the page. The documentation explains that this attribute is a bridge between HTML and JavaScript, just like classes serve as bridges between HTML and CSS. One controller can be attached to multiple elements, and one element may be powered up by multiple controllers.
  • Actions: methods to be called on specific events. They are defined in special data-action attributes.
  • Targets: important elements that can be easily accessed and manipulated. They are specified with the help of data-target attributes.

As you can see, the attributes listed above allow you to separate content from behaviour logic in a very simple and natural way. Later in this article, we will see all these concepts in action and notice how easy it is to read an HTML document and understand what's going on.

Bootstrapping a Stimulus Application

Stimulus can be easily installed as an NPM package or loaded directly via the script tag as explained in the docs. Also note that by default this framework integrates with the Webpack asset manager, which supports goodies like controller autoloading. You are free to use any other build system, but in this case some more work will be needed.

The quickest way to get started with Stimulus is by utilizing this starter project that has Express web server and Babel already hooked up. It also depends on Yarn, so be sure to install it. To clone the project and install all its dependencies, run:

git clone https://github.com/stimulusjs/stimulus-starter.git cd stimulus-starter yarn install

If you'd prefer not to install anything locally, you may remix this project on Glitch and do all the coding right in your browser.

Great—we are all set and can proceed to the next section!

Some Markup

Suppose we are creating a small single-page application that presents a list of employees and loads information like their name, photo, position, salary, birthdate, etc.

Let's start with the list of employees. All the markup that we are going to write should be placed inside the public/index.html file, which already has some very minimal HTML. For now, we will hard-code all our employees in the following way:

<h1>Our employees</h1> <div> <ul> <li><a href="#">John Doe</a></li> <li><a href="#">Alice Smith</a></li> <li><a href="#">Will Brown</a></li> <li><a href="#">Ann Grey</a></li> </ul> </div>

Nice! Now let's add a dash of Stimulus magic.

Creating a Controller

As the official documentation explains, the main purpose of Stimulus is to connect JavaScript objects (called controllers) to the DOM elements. The controllers will then bring the page to life. As a convention, controllers' names should end with a _controller postfix (which should be very familiar to Rails developers).

There is a directory for controllers already available called src/controllers. Inside, you will find a  hello_controller.js file that defines an empty class:

import { Controller } from "stimulus" export default class extends Controller { }

Let's rename this file to employees_controller.js. We don't need to specifically require it because controllers are loaded automatically thanks to the following lines of code in the src/index.js file:

const application = Application.start() const context = require.context("./controllers", true, /\.js$/) application.load(definitionsFromContext(context))

The next step is to connect our controller to the DOM. In order to do this, set a data-controller attribute and assign it an identifier (which is employees in our case):

<div data-controller="employees"> <ul> <!-- your list --> </ul> </div>

That's it! The controller is now attached to the DOM.

Lifecycle Callbacks

One important thing to know about controllers is that they have three lifecycle callbacks that get fired on specific conditions:

  • initialize: this callback happens only once, when the controller is instantiated.
  • connect: fires whenever we connect the controller to the DOM element. Since one controller may be connected to multiple elements on the page, this callback may run multiple times.
  • disconnect: as you've probably guessed, this callback runs whenever the controller disconnects from the DOM element.

Nothing complex, right? Let's take advantage of the initialize() and connect() callbacks to make sure our controller actually works:

// src/controllers/employees_controller.js export default class extends Controller { initialize() { console.log('Initialized') console.log(this) } connect() { console.log('Connected') console.log(this) } }

Next, start the server by running:

yarn start

Navigate to http://localhost:9000. Open your browser's console and make sure both messages are displayed. It means that everything is working as expected!

Adding Events

The next core Stimulus concept is events. Events are used to respond to various user actions on the page: clicking, hovering, focusing, etc. Stimulus does not try to reinvent a bicycle, and its event system is based on generic JS events.

For instance, let's bind a click event to our employees. Whenever this event happens, I would like to call the as yet non-existent choose() method of the employees_controller:

<ul> <li><a href="#" data-action="click->employees#choose">John Doe</a></li> <li><a href="#" data-action="click->employees#choose">Alice Smith</a></li> <li><a href="#" data-action="click->employees#choose">Will Brown</a></li> <li><a href="#" data-action="click->employees#choose">Ann Grey</a></li> </ul>

Probably, you can understand what's going on here by yourself.

  • data-action is the special attribute that binds an event to the element and explains what action should be called.
  • click, of course, is the event's name.
  • employees is the identifier of our controller.
  • choose is the name of the method that we'd like to call.

Since click is the most common event, it can be safely omitted:

<li><a href="#" data-action="employees#choose">John Doe</a></li>

In this case, click will be used implicitly.

Next, let's code the choose() method. I don't want the default action to happen (which is, obviously, opening a new page specified in the href attribute), so let's prevent it:

// src/controllers/employees_controller.js // callbacks here... choose(e) { e.preventDefault() console.log(this) console.log(e) }

e is the special event object that contains full information about the triggered event. Note, by the way, that this returns the controller itself, not an individual link! In order to gain access to the element that acts as the event's target, use e.target.

Reload the page, click on a list item, and observe the result!

Working With the State

Now that we have bound a click event handler to the employees, I'd like to store the currently chosen person. Why? Having stored this info, we can prevent the same employee from being selected the second time. This will later allow us to avoid loading the same information multiple times as well.

Stimulus instructs us to persist state in the Data API, which seems quite reasonable. First of all, let's provide some arbitrary ids for each employee using the data-id attribute:

<ul> <li><a href="#" data-id="1" data-action="employees#choose">John Doe</a></li> <li><a href="#" data-id="2" data-action="click->employees#choose">Alice Smith</a></li> <li><a href="#" data-id="3" data-action="click->employees#choose">Will Brown</a></li> <li><a href="#" data-id="4" data-action="click->employees#choose">Ann Grey</a></li> </ul>

Next, we need to fetch the id and persist it. Using the Data API is very common with Stimulus, so a special this.data object is provided for each controller. With its help, we can run the following methods:

  • this.data.get('name'): get the value by its attribute.
  • this.data.set('name', value): set the value under some attribute.
  • this.data.has('name'): check if the attribute exists (returns a boolean value).

Unfortunately, these shortcuts are not available for the targets of the click events, so we must stick with getAttribute() in their case:

// src/controllers/employees_controller.js choose(e) { e.preventDefault() this.data.set("current-employee", e.target.getAttribute('data-id')) }

But we can do even better by creating a getter and a setter for the currentEmployee:

// src/controllers/employees_controller.js get currentEmployee() { return this.data.get("current-employee") } set currentEmployee(id) { if (this.currentEmployee !== id) { this.data.set("current-employee", id) } }

Notice how we are using the this.currentEmployee getter and making sure that the provided id is not the same as the already stored one.

Now you may rewrite the choose() method in the following way:

// src/controllers/employees_controller.js choose(e) { e.preventDefault() this.currentEmployee = e.target.getAttribute('data-id') }

Reload the page to make sure that everything still works. You won't notice any visual changes yet, but with the help of the Inspector tool you'll notice that the ul has the data-employees-current-employee attribute with a value that changes as you click on the links. The employees part in the attribute's name is the controller's identifier and is being added automatically.

Now let's move on and highlight the currently chosen employee.

Using Targets

When an employee is selected, I would like to assign the corresponding element with a .chosen class. Of course, we might have solved this task by using some JS selector functions, but Stimulus provides a neater solution.

Meet targets, which allow you to mark one or more important elements on the page. These elements can then be easily accessed and manipulated as needed. In order to create a target, add a data-target attribute with the value of {controller}.{target_name} (which is called a target descriptor):

<ul data-controller="employees"> <li><a href="#" data-target="employees.employee" data-id="1" data-action="employees#choose">John Doe</a></li> <li><a href="#" data-target="employees.employee" data-id="2" data-action="click->employees#choose">Alice Smith</a></li> <li><a href="#" data-target="employees.employee" data-id="3" data-action="click->employees#choose">Will Brown</a></li> <li><a href="#" data-target="employees.employee" data-id="4" data-action="click->employees#choose">Ann Grey</a></li> </ul>

Now let Stimulus know about these new targets by defining a new static value:

// src/controllers/employees_controller.js export default class extends Controller { static targets = [ "employee" ] // ... }

How do we access the targets now? It's as simple as saying this.employeeTarget (to get the first element) or this.employeeTargets (to get all the elements):

// src/controllers/employees_controller.js choose(e) { e.preventDefault() this.currentEmployee = e.target.getAttribute('data-id') console.log(this.employeeTargets) console.log(this.employeeTarget) }

Great! How can these targets help us now? Well, we can use them to add and remove CSS classes with ease based on some criteria:

// src/controllers/employees_controller.js choose(e) { e.preventDefault() this.currentEmployee = e.target.getAttribute('data-id') this.employeeTargets.forEach((el, i) => { el.classList.toggle("chosen", this.currentEmployee === el.getAttribute("data-id")) }) }

The idea is simple: we iterate over an array of targets and for each target compare its data-id to the one stored under this.currentEmployee. If it matches, the element is assigned the .chosen class. Otherwise, this class is removed. You may also extract the if (this.currentEmployee !== id) { condition from the setter and use it in the chosen() method instead:

// src/controllers/employees_controller.js choose(e) { e.preventDefault() const id = e.target.getAttribute('data-id') if (this.currentEmployee !== id) { // <--- this.currentEmployee = id this.employeeTargets.forEach((el, i) => { el.classList.toggle("chosen", id === el.getAttribute("data-id")) }) } }

Looking nice! Lastly, we'll provide some very simple styling for the .chosen class inside the public/main.css:

.chosen { font-weight: bold; text-decoration: none; cursor: default; }

Reload the page once again, click on a person, and make sure that person is being highlighted properly.

Loading Data Asynchronously

Our next task is to load information about the chosen employee. In a real-world application, you would have to set up a hosting provider, a back-end powered by something like Django or Rails, and an API endpoint that responds with JSON containing all the necessary data. But we are going to make things a bit simpler and concentrate on the client side only. Create an employees directory under the public folder. Next, add four files containing data for individual employees:

1.json

{ "name": "John Doe", "gender": "male", "age": "40", "position": "CEO", "salary": "$120.000/year", "image": "https://burst.shopifycdn.com/photos/couple-in-love-at-sunset_373x.jpg" }

2.json

{ "name": "Alice Smith", "gender": "female", "age": "32", "position": "CTO", "salary": "$100.000/year", "image": "https://burst.shopifycdn.com/photos/woman-listening-at-team-meeting_373x.jpg" }

3.json

{ "name": "Will Brown", "gender": "male", "age": "30", "position": "Tech Lead", "salary": "$80.000/year", "image": "https://burst.shopifycdn.com/photos/casual-urban-menswear_373x.jpg" }

4.json

{ "name": "Ann Grey", "gender": "female", "age": "25", "position": "Junior Dev", "salary": "$20.000/year", "image": "https://burst.shopifycdn.com/photos/woman-using-tablet_373x.jpg" }

All photos were taken from the free stock photography by Shopify called Burst.

Our data is ready and waiting to be loaded! In order to do this, we'll code a separate loadInfoFor() method:

// src/controllers/employees_controller.js loadInfoFor(employee_id) { fetch(`employees/${employee_id}.json`) .then(response => response.text()) .then(json => { this.displayInfo(json) }) }

This method accepts an employee's id and sends an asynchronous fetch request to the given URI. There are also two promises: one to fetch the body and another one to display the loaded info (we'll add the corresponding method in a moment).

Utilize this new method inside choose():

// src/controllers/employees_controller.js choose(e) { e.preventDefault() const id = e.target.getAttribute('data-id') if (this.currentEmployee !== id) { this.loadInfoFor(id) // ... } }

Before coding the displayInfo() method, we need an element to actually render the data to. Why don't we take advantage of targets once again?

<!-- public/index.html --> <div data-controller="employees"> <div data-target="employees.info"></div> <ul> <!-- ... --> </ul> </div>

Define the target:

// src/controllers/employees_controller.js export default class extends Controller { static targets = [ "employee", "info" ] // ... }

And now utilize it to display all the info:

// src/controllers/employees_controller.js displayInfo(raw_json) { const info = JSON.parse(raw_json) const html = `<ul><li>Name: ${info.name}</li><li>Gender: ${info.gender}</li><li>Age: ${info.age}</li><li>Position: ${info.position}</li><li>Salary: ${info.salary}</li><li><img src="${info.image}"></li></ul>` this.infoTarget.innerHTML = html }

Of course, you are free to employ a templating engine like Handlebars, but for this simple case that would probably be overkill.

Now reload the page and choose one of the employees. His bio and image should be loaded nearly instantly, which means our app is working properly!

Dynamic List of Employees

Using the approach described above, we can go even further and load the list of employees on the fly rather than hard-coding it.

Prepare the data inside the public/employees.json file:

[ { "id": "1", "name": "John Doe" }, { "id": "2", "name": "Alice Smith" }, { "id": "3", "name": "Will Brown" }, { "id": "4", "name": "Ann Grey" } ]

Now tweak the public/index.html file by removing the hard-coded list and adding a data-employees-url attribute (note that we must provide the controller's name, otherwise the Data API won't work):

<div data-controller="employees" data-employees-url="/employees.json"> <div data-target="employees.info"></div> </div>

As soon as controller is attached to the DOM, it should send a fetch request to build a list of employees. It means that the connect() callback is the perfect place to do this:

// src/controllers/employees_controller.js connect() { this.loadFrom(this.data.get('url'), this.displayEmployees) }

I propose we create a more generic loadFrom() method that accepts a URL to load data from and a callback to actually render this data:

// src/controllers/employees_controller.js loadFrom(url, callback) { fetch(url) .then(response => response.text()) .then(json => { callback.call( this, JSON.parse(json) ) }) }

Tweak the choose() method to take advantage of the loadFrom():

// src/controllers/employees_controller.js choose(e) { e.preventDefault() const id = e.target.getAttribute('data-id') if (this.currentEmployee !== id) { this.loadFrom(`employees/${id}.json`, this.displayInfo) // <--- this.currentEmployee = id this.employeeTargets.forEach((el, i) => { el.classList.toggle("chosen", id === el.getAttribute("data-id")) }) } }

displayInfo() can be simplified as well, since JSON is now being parsed right inside the loadFrom():

// src/controllers/employees_controller.js displayInfo(info) { const html = `<ul><li>Name: ${info.name}</li><li>Gender: ${info.gender}</li><li>Age: ${info.age}</li><li>Position: ${info.position}</li><li>Salary: ${info.salary}</li><li><img src="${info.image}"></li></ul>` this.infoTarget.innerHTML = html }

Remove loadInfoFor() and code the displayEmployees() method:

// src/controllers/employees_controller.js displayEmployees(employees) { let html = "<ul>" employees.forEach((el) => { html += `<li><a href="#" data-target="employees.employee" data-id="${el.id}" data-action="employees#choose">${el.name}</a></li>` }) html += "</ul>" this.element.innerHTML += html }

That's it! We are now dynamically rendering our list of employees based on the data returned by the server.

Conclusion

In this article we have covered a modest JavaScript framework called Stimulus. We have seen how to create a new application, add a controller with a bunch of callbacks and actions, and introduce events and actions. Also, we've done some asynchronous data loading with the help of fetch requests.

All in all, that's it for the basics of Stimulus—it really does not expect you to have some arcane knowledge in order to craft web applications. Of course, the framework will probably have some new features in future, but the developers are not planning to turn it into a huge monster with hundreds of tools. 

If you'd like to find more examples of using Stimulus, you may also check out this tiny handbook. And if you’re looking for additional JavaScript resources to study or to use in your work, check out what we have available in the Envato Market

Did you like Stimulus? Would you be interested in trying to create a real-world application powered by this framework? Share your thoughts in the comments!

As always, I thank you for staying with me and until the next time.

Categories: Web Design

Single-Page React Applications With the React-Router and React-Transition-Group Modules

Fri, 04/20/2018 - 05:00

This tutorial will walk you through using the react-router and react-transition-group modules to create multi-page React applications with page transition animations.

Preparing the React AppInstalling the create-react-app Package

If you've ever had the chance to try React, you've probably heard about the create-react-app package, which makes it super easy to start with a React development environment.

In this tutorial, we will use this package to initiate our React app.

So, first of all, make sure you have Node.js installed on your computer. It will also install npm for you.

In your terminal, run npm install -g create-react-app. This will globally install create-react-app on your computer.

Once it is done, you can verify whether it is there by typing create-react-app -V.

Creating the React Project

Now it's time to build our React project. Just run create-react-app multi-page-app. You can, of course, replace multi-page-app with anything you want.

Now, create-react-app will create a folder named multi-page-app. Just type cd multi-page-app to change directory, and now run npm start to initialize a local server.

That's all. You have a React app running on your local server.

Now it's time to clean the default files and prepare our application.

In your src folder, delete everything but App.js and index.js. Then open index.js and replace the content with the code below.

import React from 'react'; import ReactDOM from 'react-dom'; import App from './App'; ReactDOM.render(<App />, document.getElementById('root'));

I basically deleted the registerServiceWorker related lines and also the import './index.css'; line.

Also, replace your App.js file with the code below.

import React, { Component } from 'react'; class App extends Component { render() { return ( <div className="App"> </div> ); } } export default App;

Now we will install the required modules.

In your terminal, type the following commands to install the react-router and react-transition-group modules respectively.

npm install react-router-dom --save

npm install react-transition-group@1.x --save

After installing the packages, you can check the package.json file inside your main project directory to verify that the modules are included under dependencies.

Router Components

There are basically two different router options: HashRouter and BrowserRouter.

As the name implies, HashRouter uses hashes to keep track of your links, and it is suitable for static servers. On the other hand, if you have a dynamic server, it is a better option to use BrowserRouter, considering the fact that your URLs will be prettier.

Once you decide which one you should use, just go ahead and add the component to your index.js file.

import { HashRouter } from 'react-router-dom'

The next thing is to wrap our <App> component with the router component.

So your final index.js file should look like this:

import React from 'react'; import ReactDOM from 'react-dom'; import { HashRouter } from 'react-router-dom' import App from './App'; ReactDOM.render(<HashRouter><App/></HashRouter>, document.getElementById('root'));

If you're using a dynamic server and prefer to use BrowserRouter, the only difference would be importing the BrowserRouter and using it to wrap the <App> component.

By wrapping our <App> component, we are serving the history object to our application, and thus other react-router components can communicate with each other.

Inside <App/> Component

Inside our <App> component, we will have two components named <Menu> and <Content>. As the names imply, they will hold the navigation menu and displayed content respectively.

Create a folder named "components" in your src directory, and then create the Menu.js and Content.js files.

Menu.js

Let's fill in our Menu.js component.

It will be a stateless functional component since we don't need states and life-cycle hooks.

import React from 'react' const Menu = () =>{ return( <ul> <li>Home</li> <li>Works</li> <li>About</li> </ul> ) } export default Menu

Here we have a <ul> tag with <li> tags, which will be our links.

Now add the following line to your Menu component.

import { Link } from 'react-router-dom'

And then wrap the content of the <li> tags with the <Link> component.

The <Link> component is essentially a react-router component acting like an <a> tag, but it does not reload your page with a new target link.

Also, if you style your a tag in CSS, you will notice that the <Link> component gets the same styling.

Note that there is a more advanced version of the <Link> component, which is <NavLink>. This offers you extra features so that you can style the active links.

Now we need to define where each link will navigate. For this purpose, the <Link> component has a to prop.

import React from 'react' import { Link } from 'react-router-dom' const Menu = () =>{ return( <ul> <li><Link to="/">Home</Link></li> <li><Link to="/works">Works</Link></li> <li><Link to="/about">About</Link></li> </ul> ) } export default MenuContent.js

Inside our <Content> component, we will define the Routes to match the Links.

We need the Switch and Route components from react-router-dom. So, first of all, import them.

import { Switch, Route } from 'react-router-dom'

Second of all, import the components that we want to route to. These are the Home, Works and About components for our example. Assuming you have already created those components inside the components folder, we also need to import them.

import Home from './Home'

import Works from './Works'

import About from './About'

Those components can be anything. I just defined them as stateless functional components with minimum content. An example template is below. You can use this for all three components, but just don't forget to change the names accordingly.

import React from 'react' const Home = () =>{ return( <div> Home </div> ) } export default HomeSwitch

We use the <Switch> component to group our <Route> components. Switch looks for all the Routes and then returns the first matching one.

Route

Routes are components calling your target component if it matches the path prop.

The final version of our Content.js file looks like this:

import React from 'react' import { Switch, Route } from 'react-router-dom' import Home from './Home' import Works from './Works' import About from './About' const Content = () =>{ return( <Switch> <Route exact path="/" component={Home}/> <Route path="/works" component={Works}/> <Route path="/about" component={About}/> </Switch> ) } export default Content

Notice that the extra exact prop is required for the Home component, which is the main directory. Using exact forces the Route to match the exact pathname. If it's not used, other pathnames starting with / would also be matched by the Home component, and for each link, it would only display the Home component.

Now when you click the menu links, your app should be switching the content.

Animating the Route Transitions

So far, we have a working router system. Now we will animate the route transitions. In order to achieve this, we will use the react-transition-group module.

We will be animating the mounting state of each component. When you route different components with the Route component inside Switch, you are essentially mounting and unmounting different components accordingly.

We will use react-transition-group in each component we want to animate. So you can have a different mounting animation for each component. I will only use one animation for all of them.

As an example, let's use the <Home> component.

First, we need to import CSSTransitionGroup.

import { CSSTransitionGroup } from 'react-transition-group'

Then you need to wrap your content with it.

Since we are dealing with the mounting state of the component, we enable transitionAppear and set a timeout for it. We also disable transitionEnter and transitionLeave, since these are only valid once the component is mounted. If you are planning to animate any children of the component, you have to use them.

Lastly, add the specific transitionName so that we can refer to it inside the CSS file.

import React from 'react' import { CSSTransitionGroup } from 'react-transition-group' import '../styles/homeStyle.css' const Home = () =>{ return( <CSSTransitionGroup transitionName="homeTransition" transitionAppear={true} transitionAppearTimeout={500} transitionEnter={false} transitionLeave={false}> <div> Home </div> </CSSTransitionGroup> ) } export default Home

We also imported a CSS file, where we define the CSS transitions.

.homeTransition-appear{ opacity: 0; } .homeTransition-appear.homeTransition-appear-active{ opacity: 1; transition: all .5s ease-in-out; }

If you refresh the page, you should see the fade-in effect of the Home component.

If you apply the same procedure to all the other routed components, you will see their individual animations when you change the content with your Menu.

Conclusion

In this tutorial, we covered the react-router-dom and react-transition-group modules. However, there's more to both modules than we covered in this tutorial. Here is a working demo of what was covered.

So, to learn more features, always go through the documentation of the modules you are using.

Over the last couple of years, React has grown in popularity. In fact, we have a number of items in the marketplace that are available for purchase, review, implementation, and so on. If you’re looking for additional resources around React, don’t hesitate to check them out.

Categories: Web Design

Testing in Laravel

Wed, 04/18/2018 - 05:00

Irrespective of the application you're dealing with, testing is an important and often overlooked aspect that you should give the attention it deserves. Today, we're going to discuss it in the context of the Laravel web framework.

In fact, Laravel already supports the PHPUnit testing framework in the core itself. PHPUnit is one of the most popular and widely accepted testing frameworks across the PHP community. It allows you to create both kinds of tests—unit and functional.

We'll start with a basic introduction to unit and functional testing. As we move on, we'll explore how to create unit and functional tests in Laravel. I assume that you're familiar with basics of the PHPUnit framework as we will explore it in the context of Laravel in this article.

Unit and Functional Tests

If you're already familiar with the PHPUnit framework, you should know that you can divide tests into two flavors—unit tests and functional tests.

In unit tests, you test the correctness of a given function or a method. More importantly, you test a single piece of your code's logic at a given time.

In your development, if you find that the method you've implemented contains more than one logical unit, you're better off splitting that into multiple methods so that each method holds a single logical and testable piece of code.

Let's have a quick look at an example that's an ideal case for unit testing.

public function getNameAttribute($value) { return ucfirst($value); }

As you can see, the method does one and only one thing. It uses the ucfirst function to convert a title into a title that starts with uppercase.

Whereas the unit test is used to test the correctness of a single logical unit of code, the functional test, on the other hand, allows you to test the correctness of a specific use case. More specifically, it allows you to simulate actions a user performs in an application in order to run a specific use case.

For example, you could implement a functional test case for some login functionality that may involve the following steps.

  • Create the GET request to access the login page.
  • Check if we are on the login page.
  • Generate the POST request to post data to the login page.
  • Check if the session was created successfully.

So that's how you're supposed to create the functional test case. From the next section onward, we'll create examples that demonstrate how to create unit and functional test cases in Laravel.

Setting Up the Prerequisites

Before we go ahead and create actual tests, we need to set up a couple of things that'll be used in our tests.

We will create the Post model and related migration to start with. Go ahead and run the following artisan command to create the Post model.

$php artisan make:model Post --migration

The above command should create the Post model class and an associated database migration as well.

The Post model class should look like:

<?php // app/Post.php namespace App; use Illuminate\Database\Eloquent\Model; class Post extends Model { // }

And the database migration file should be created at database/migrations/YYYY_MM_DD_HHMMSS_create_posts_table.php.

We also want to store the title of the post. Let's revise the code of the Post database migration file to look like the following.

<?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreatePostsTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('posts', function (Blueprint $table) { $table->increments('id'); $table->string('name'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('posts'); } }

As you can see, we've added the $table->string('name') column to store the title of the post. Next, you just need to run the migrate command to actually create that table in the database.

$php artisan migrate

Also, let's replace the Post model with the following contents.

<?php namespace App; use Illuminate\Database\Eloquent\Model; class Post extends Model { /** * Get the post title. * * @param string $value * @return string */ public function getNameAttribute($value) { return ucfirst($value); } }

We've just added the accessor method, which modifies the title of the post, and that's exactly what we'll test in our unit test case. That's it as far as the Post model is concerned.

Next, we'll create a controller file at app/Http/Controllers/AccessorController.php. It'll be useful to us when we create the functional test case at a later stage.

<?php // app/Http/Controllers/AccessorController.php namespace App\Http\Controllers; use App\Post; use Illuminate\Http\Request; use App\Http\Controllers\Controller; class AccessorController extends Controller { public function index(Request $request) { // get the post-id from request params $post_id = $request->get("id", 0); // load the requested post $post = Post::find($post_id); // check the name property return $post->name; } }

In the index method, we retrieve the post id from the request parameters and try to load the post model object.

Let's add an associated route as well in the routes/web.php file.

Route::get('accessor/index', 'AccessorController@index');

And with that in place, you can run the http://your-laravel-site.com/accessor/index URL to see if it works as expected.

Unit Testing

In the previous section, we did the initial setup that's going to be useful to us in this and upcoming sections. In this section, we are going to create an example that demonstrates the concepts of unit testing in Laravel.

As always, Laravel provides an artisan command that allows you to create the base template class of the unit test case.

Run the following command to create the AccessorTest unit test case class. It's important to note that we're passing the --unit keyword that creates the unit test case, and it'll be placed under the tests/Unit directory.

$php artisan make:test AccessorTest --unit

And that should create the following class at tests/Unit/AccessorTest.php.

<?php // tests/Unit/AccessorTest.php namespace Tests\Unit; use Tests\TestCase; use Illuminate\Foundation\Testing\DatabaseMigrations; use Illuminate\Foundation\Testing\DatabaseTransactions; class AccessorTest extends TestCase { /** * A basic test example. * * @return void */ public function testExample() { $this->assertTrue(true); } }

Let's replace it with some meaningful code.

<?php // tests/Unit/AccessorTest.php namespace Tests\Unit; use Tests\TestCase; use Illuminate\Foundation\Testing\DatabaseMigrations; use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Support\Facades\DB; use App\Post; class AccessorTest extends TestCase { /** * Test accessor method * * @return void */ public function testAccessorTest() { // load post manually first $db_post = DB::select('select * from posts where id = 1'); $db_post_title = ucfirst($db_post[0]->name); // load post using Eloquent $model_post = Post::find(1); $model_post_title = $model_post->name; $this->assertEquals($db_post_title, $model_post_title); } }

As you can see, the code is exactly the same as it would have been in core PHP. We've just imported Laravel-specific dependencies that allow us to use the required APIs. In the testAccessorTest method, we're supposed to test the correctness of the getNameAttribute method of the Post model.

To do that, we've fetched an example post from the database and prepared the expected output in the $db_post_title variable. Next, we load the same post using the Eloquent model that executes the getNameAttribute method as well to prepare the post title. Finally, we use the assertEquals method to compare both variables as usual.

So that's how to prepare unit test cases in Laravel.

Functional Testing

In this section, we'll create the functional test case that tests the functionality of the controller that we created earlier.

Run the following command to create the AccessorTest functional test case class. As we're not using the --unit keyword, it'll be treated as a functional test case and placed under the tests/Feature directory.

$php artisan make:test AccessorTest

It'll create the following class at tests/Feature/AccessorTest.php.

<?php // tests/Feature/AccessorTest.php namespace Tests\Feature; use Tests\TestCase; use Illuminate\Foundation\Testing\WithoutMiddleware; use Illuminate\Foundation\Testing\DatabaseMigrations; use Illuminate\Foundation\Testing\DatabaseTransactions; class AccessorTest extends TestCase { /** * A basic test example. * * @return void */ public function testExample() { $this->assertTrue(true); } }

Let's replace it with the following code.

<?php // tests/Feature/AccessorTest.php namespace Tests\Feature; use Tests\TestCase; use Illuminate\Foundation\Testing\WithoutMiddleware; use Illuminate\Foundation\Testing\DatabaseMigrations; use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Support\Facades\DB; class AccessorTest extends TestCase { /** * A basic test example. * * @return void */ public function testBasicTest() { // load post manually first $db_post = DB::select('select * from lvl_posts where id = 1'); $db_post_title = ucfirst($db_post[0]->name); $response = $this->get('/accessor/index?id=1'); $response->assertStatus(200); $response->assertSeeText($db_post_title); } }

Again, the code should look familiar to those who have prior experience in functional testing.

Firstly, we're fetching an example post from the database and preparing the expected output in the $db_post_title variable. Following that, we try to simulate the /accessor/index?id=1 GET request and grab the response of that request in the $response variable.

Next, we've tried to match the response code in the $response variable with the expected response code. In our case, it should be 200 as we should get a valid response for our GET request. Further, the response should contain a title that starts with uppercase, and that's exactly what we're trying to match using the assertSeeText method.

And that's an example of the functional test case. Now, we have everything we could run our tests against. Let's go ahead and run the following command in the root of your application to run all tests.

$phpunit

That should run all tests in your application. You should see a standard PHPUnit output that displays the status of tests and assertions in your application.

And with that, we're at the end of this article.

Conclusion

Today, we explored the details of testing in Laravel, which already supports PHPUnit in its core. The article started with a basic introduction to unit and functional testing, and as we moved on we explored the specifics of testing in the context of Laravel.

In the process, we created a handful of examples that demonstrated how you could create unit and functional test cases using the artisan command.

If you're just getting started with Laravel or looking to expand your knowledge, site, or application with extensions, we have a variety of things you can study in Envato Market.

Don't hesitate to express your thoughts using the feed below!

Categories: Web Design

12 Best Contact Form PHP Scripts

Mon, 04/16/2018 - 05:53

Contact forms are a must have for every website. They encourage your site visitors to engage with you while potentially lowering the amount of spam you get. 

For businesses, this engagement with visitors increases the chances of turning them into clients or customers and thus increasing revenue. 

Whether your need is for a simple three-line contact form or a more complex one that offers loads of options and functions, you’re sure to find the right PHP contact form here in our 12 Best Contact Form PHP Scripts on CodeCanyon.

1. Quform- Responsive AJAX Contact Form

There's a reason Quform- Responsive AJAX Contact Form is one of the best-selling PHP contact forms at CodeCanyon. This versatile AJAX contact form can be adapted to be a register form, quote form, or any other form needed. With tons of other customisations available, Quform- Responsive AJAX Contact Form is bound to keep the most discerning user happy.

Best features:

  • three ready-to-use themes with six variations
  • ability to integrate into your own theme design
  • ability to create complex form layouts
  • file uploads supported
  • and more

User DigitalOxide says:

"This script is incredible! It is very detailed instructions, examples and is very fully featured. I can't think of anything I could ever need (as far as forms go) that this script is not able to accomplish!"2. KONTAKTO

KONTAKTO only entered the market in March of 2017 but has already developed a name for itself as one of the top-rated scripts in this category. The standout feature of this beautifully designed contact form is the stylish map with a location pin that comes integrated in the form.

Best features:

  • required field validation
  • anti-spam with simple Captcha math
  • defaults to PHP mail but SMTP option available
  • repeat submission prevention
  • and more

User vholecek says:

"The design is outstanding and the author is very responsive to questions. I got in a little over my head on the deployment of the template and the author had it sorted out in less than 24 hours."3. ContactMe

ContactMe is an incredibly versatile and easily customisable contact form. With 28 ready-to-use styles and 4 different themes, the sky's the limit when it comes to creating the ideal form to fit your needs. 

Best features:

  • easy to install and customise
  • supports both versions of Google reCAPTCHA
  • multiple forms per page allowed
  • four sizes of the form available 
  • and more

User ddglobal says:

"Great plugin for Contact Form. Excellent code, variety & flexibility, incredible fast and outstanding support!"4. PHP Form Builder

Another CodeCanyon top seller, PHP Form Builder includes the jQuery live validation plugin which enables you to build any type of form, connect your database, insert, update or delete records, and send your emails using customisable HTML/CSS templates.

Best features:

  • over 50 prebuilt templates included
  • accepts any HTML5 form elements
  • default options ready for Bootstrap
  • email sending 
  • and more

User sflahaut says:

"Excellent product containing ready to use examples of all types of forms. Documentation is excellent and customer support is exceptional as many others have commented previously. I highly recommend this as it can save a lot of time, especially for developers with not a lot of web experience like myself."5. Contact Framework

Contact Framework has been around for a while, and it’s just gotten better and better with each new update. Its simple yet modern design comes in three themes and five colours, giving you a lot of options for customisation and integration into your site design. 

Best features:

  • ability to attach files
  • supports both versions of Google reCAPTCHA and math CAPTCHA
  • customisable redirect messages
  • customisable notification messages
  • and more 

User fatheaddrummer says:

“Awesome flexibility. The forms look awesome. Outstanding customer support! 6. SLEEK Contact Form

Having made its debut in 2017, SLEEK Contact Form is one of the newest PHP contact form scripts on CodeCanyon. With its simple and stylish design and functionality, it is ideal for creatives or those looking to bring a bit of cool style to their website's contact form.

Best features:

  • invisible Google reCaptcha anti-spam system
  • ability to add attachments of any type
  • automatically get the IP and location of the sender by email
  • easy to modify and implement new fields
  • and more

User thernztrom says:

"Just what I wanted. Good support from author!"7. Ultimate PHP, HTML5 & AJAX Contact Form

The Ultimate PHP, HTML5 and AJAX Contact Form replaces the hugely successful AJAX Contact Form and allows you to easily place and manage a self-contained contact form on any page of your existing PHP website.

Best features:

  • supports file uploads to attach to email
  • field type validation
  • multiple forms per page allowed
  • Google reCAPTCHA capable
  • and more

User geudde says:

"Awesome coding and impeccable documentation. I had the form embedded in my website in less than 10 minutes, and most of that time was spent signing up with Google for reCAPTCHA. I purchased the same author's AJAX form years ago. The new version is so much more elegant and blends seamlessly into my site."8. Perfect Contact Us Form

Perfect Contact Us Form is a Bootstrap-based form which is fully customisable and easy to use. The easy-to-use form integrates well with HTML and PHP pages and will appeal to both beginners and more experienced developers alike.

Best features:

  • AJAX based
  • both SMTP and PHP email script
  • jQuery-based Captcha is included for anti-spam
  • and more

User andreahale says:

"Excellent support and super fast response time. Quickly helped me with the modifications I wanted to make to the form."
9. Contact Form Generator

Contact Form Generator is another of CodeCanyon’s best-selling PHP Contact Form Scripts. It features a user-friendly drag-and-drop interface that helps you build contact forms, feedback forms, online surveys, event registrations, etc., and get responses via email in a matter of minutes. It is a highly effective form builder that enables you to create well-designed contact forms and extend their range to include other functions.

Best features:

  • instant email or SMS notifications
  • custom email auto-responder
  • integrated with MailChimp, AWeber, and five other email subscription services
  • anti-spam protection
  • and more

User Enrico333 says:

"Forms have been a pain for as long as I can recall - this has truly made my life easier."

10. Feedback Form

Really, a feedback form is more limited in its function than a general contact form, but as contact forms can also be used to leave feedback, I thought why not include a bona fide feedback form in this list. 

Feedback Form allows your users to rate your product or service and get the kind of in-depth feedback necessary to improve your business. Feedback Form is super easy to use and can be added to any website in the shortest amount of time. 

Best features: 

  • multi-purpose feedback form 
  • fully customisable 
  • pop-up form (no page reload) 
  • form validation 
  • and more

User diwep06 says:

"Thanks for the Script ... Ultra nice, simple to set up and no skill needed."11. ContactPLUS+ PHP Contact Form

ContactPlus+ is a clean and simple contact form which comes in three styles: an unstyled version that you can build to suit your taste, a normal form with just the essential information needed on a contact form, and a longer form to accommodate an address.

Best features:

  • Captcha verification
  • successful submission message
  • two styled versions and one unstyled version
  • and more

User itscody says:

"He went above and beyond to make sure this worked as I wanted with the overly complicated design of my website."12. Easy Contact Form With Attachments

Though not the prettiest contact form in this list, Easy Contact Form With Attachments is certainly one of the easiest to add to your site. Furthermore, configuration requires just your email address and company info. The form offers five different themes to choose from and, as the name suggests, allows you to send file attachments.

Best features:

  • attachment file size limit can be adjusted up from default of 5MB
  • user friendly with one-click human verification against spam bots
  • optional phone number field and company information
  • error messages can be easily modified
  • and more

User powerj says:

"Excellent support! Great code quality and best customer service!"Conclusion

These 12 Best Contact Form PHP Scripts just scratch the surface of products available at Envato Market, so if none of them fit your needs, there are plenty of other great options you may prefer.

And if you want to improve your PHP skills, check out the ever so useful free PHP tutorials we have on offer.

Categories: Web Design

Getting Started With the Mojs Animation Library: The ShapeSwirl and Stagger Modules

Mon, 04/16/2018 - 05:00

The first and second tutorials of this series covered how to animate different HTML elements and SVG shapes using mojs. In this tutorial, we will learn about two more modules which can make our animations more interesting. The ShapeSwirl module allows you to add a swirling motion to any shape that you create. The stagger module, on the other hand, allows you to create and animate multiple shapes at once.

Using the ShapeSwirl Module

The ShapeSwirl module in mojs has a constructor which accepts all the properties of the Shape module. It also accepts some additional properties which allow it to create a swirling motion.

You can specify the amplitude or size of the swirl using the swirlSize property. The oscillation frequency during the swirling motion is determined by the value of the swirlFrequency property. You can also scale down the total path length of the swirling shape using the pathScale property. Valid values for this property range between 0 and 1. The direction of the motion can be specified using the direction property. Keep in mind that direction only has two valid values: -1 and 1. The shapes in a swirling motion will follow a sinusoidal path by default. However, you can animate them along straight lines by setting the value of isSwirl property to false.

Besides these additional properties, the ShapeSwirl module also changes the default value of some properties from the Shape module. The radius of any swirling shape is set to 5 by default. Similarly, the scale property is set to be animated from 1 to 0 in the ShapeSwirl module.

In the following code snippet, I have used all these properties to animate two circles in a swirling motion.

var circleSwirlA = new mojs.ShapeSwirl({ parent: ".container", shape: "circle", fill: "red", stroke: "black", radius: 20, y: { 0: 200 }, angle: { 0: 720 }, duration: 2000, repeat: 10 }); var circleSwirlB = new mojs.ShapeSwirl({ parent: ".container", shape: "circle", fill: "green", stroke: "black", radius: 20, y: { 0: 200 }, angle: { 0: 720 }, duration: 2000, swirlSize: 20, swirlFrequency: 10, isSwirl: true, pathScale: 0.5, repeat: 10 });

In the following demo, you can click on the Play button to animate two circles, a triangle and a cross in a swirling motion. 

Using the Stagger Module

Unlike all other modules that we have discussed so far, stagger is not a constructor. This module is actually a function which can be wrapped around any other module to animate multiple shapes or elements at once. This can be very helpful when you want to apply the same animation sequence on different shapes but still change their magnitude independently.

Once you have wrapped the Shape module inside the stagger() function, you will be able to specify the number of elements to animate using the quantifier property. After that, you can specify the value of all other Shape related properties. It will now become possible for each property to accept an array of values to be applied on individual shapes sequentially. If you want all shapes to have the same value for a particular property, you can just set the property to be equal to that particular value instead of an array of values.

The following example should clarify how the values are assigned to different shapes:

var staggerShapes = mojs.stagger(mojs.Shape); var triangles = new staggerShapes({ quantifier: 5, shape: 'polygon', fill: 'yellow', stroke: 'black', strokeWidth: 5, radius: [20, 30, 40, 50, 60], left: 100, top: 200, x: [{0: 100}, {0: 150}, {0: 200}, {0: 250}, {0: 300}], duration: 2000, repeat: 10, easing: 'quad.in', isYoyo: true, isShowStart: true });

We begin by wrapping the Shape module inside the stagger() function. This allows us to create multiple shapes at once. We have set the value of the quantifier property to 5. This creates five different shapes, which in our case are polygons. Each polygon is a triangle because the default value of the points property is 3. We have already covered all these properties in the second tutorial of the series.

There is only one value of fill, stroke, and strokeWidth. This means that all the triangles will be filled with yellow and will have a black stroke. The width of stroke in each case would be 5px. The value of the radius property, on the other hand, is an array of five integers. Each integer determines the radius of one triangle in the group. The value 20 is assigned to the first triangle, and the value 60 is assigned to the last triangle.

All the properties have had the same initial and final values for the individual triangles so far. This means that none of the properties would be animated. However, the value of the x property is an array of objects containing the initial and final value of the horizontal position of each triangle. The first triangle will translate from x:0 to x:100, and the last triangle will translate from x:0 to x:300. The animation duration in each case would be 2000 milliseconds.

If there is a fixed step between different values of a property, you can also use stagger strings to specify the initial value and the increments. Stagger strings accept two parameters. The first is the start value, which is assigned to the first element in the group. The second value is step, which determines the increase or decrease in value for each successive shape. When only one value is passed to the stagger string, it is considered to be the step, and the start value in this case is assumed to be zero.

The triangle example above could be rewritten as:

var staggerShapes = mojs.stagger(mojs.Shape); var triangles = new staggerShapes({ quantifier: 5, shape: 'polygon', fill: 'yellow', stroke: 'black', strokeWidth: 5, radius: 'stagger(20, 10)', left: 100, top: 200, x: {0: 'stagger(100, 50)'}, duration: 2000, repeat: 10, easing: 'quad.in', isYoyo: true, isShowStart: true });

You can also assign random values to different shapes in a group using rand strings. You just have to supply a minimum and maximum value to a rand string, and mojs will automatically assign a value between these limits to individual shapes in the group.

In the following example, we are using the rand strings to randomly set the number of points for each polygon. You may have noticed that the total number of polygons we are rendering is 25, but the fill array only has four colors. When the array length is smaller than the value of the quantifier, the values for different shapes are determined by continuously cycling through the array until all the shapes have been assigned a value. For example, after assigning the color of the first four polygons, the color of the fifth polygon would be orange, the color of the sixth polygon would be yellow, and so on.

The stagger string sets the radius of the first polygon equal to 10 and then keeps increasing the radius of subsequent polygons by 1. The horizontal position of each polygon is similarly increased by 20, and the vertical position is determined randomly. The final angle value for each polygon is randomly set between -120 and 120. This way, some polygons rotate in a clockwise direction while others rotate in an anti-clockwise direction. The angle animation is also given its own easing function, which is different from the common animation of other properties.

var staggerShapes = mojs.stagger(mojs.Shape); var polygons = new staggerShapes({ quantifier: 25, shape: 'polygon', points: 'rand(3, 6)', fill: ['orange', 'yellow', 'cyan', 'lightgreen'], stroke: 'black', radius: 'stagger(10, 1)', left: 100, top: 100, x: 'stagger(0, 20)', y: 'rand(40, 400)', scale: {1: 'rand(0.1, 3)'}, angle: {0: 'rand(-120, 120)', easing: 'elastic.in'}, duration: 1000, repeat: 10, easing: 'cubic.in', isYoyo: true, isShowStart: true });

Final Thoughts

We covered two more mojs modules in this tutorial. The ShapeSwirl module allows us to animate different shapes in a swirling motion. The stagger module allows us to animate multiple shape elements at once.

Each shape in a stagger group can be animated independently without any interference from other shapes. This makes the stagger module incredibly useful. We also learned how to use stagger strings to assign values with fixed steps to properties of different shapes.

If you have any questions related to this tutorial, please let me know in the comments. We will learn about the Burst module in the next tutorial of this series.

For additional resources to study or to use in your work, check out what we have available in the Envato Market.

Categories: Web Design

Getting Started With the Mojs Animation Library: The Shape Module

Fri, 04/13/2018 - 05:00

In the previous tutorial, we used mojs to animate different HTML elements on a webpage. We used the library to mainly animate div elements which looked like squares or circles. However, you can use the Html module to animate all kinds of elements like images or headings. If you actually intend to animate basic shapes using mojs, you should probably use the Shape module from the library.

The Shape module allows you to create basic shapes in the DOM using SVG. All you have to do is specify the type of shape that you want to create, and mojs will take care of the rest. This module also allows you to animate different shapes that you create. 

In this tutorial, we will cover the basics of the Shape module and how you can use it to create different shapes and animate them.

Creating Shapes in Mojs

You need to instantiate a mojs Shape object in order to create different shapes. This object will accept different parameters which can be used to control the color, size, angle, etc. of the shapes that you create.

By default, any shape that you create will use the document body as its parent. You can specify any other element as its parent using the parent property. You can also assign a class to any shape that you create with the help of the className property. The library will not assign any default class if you skip this property.

Mojs has eight different shapes built in so that you can create them directly by setting a value for the shape property. You can set its value to circle to create circles, rect to create rectangles, and polygon to create polygons. You can also draw straight lines by setting the value of shape to be lines. The library will draw two perpendicular lines if the shape value is cross and a number of parallel lines if the shape is equal. Similarly, zigzag lines can be created by setting the property value to zigzag.

The shape object also has a points property which has different meanings for different shapes. It determines the total number of sides in a polygon and the total number of parallel lines in an equal shape. The points property can also be used to set the number of bends in a zigzag line.

As I mentioned earlier, mojs creates all these shapes using SVG. This means that the Shape object will also have some SVG specific properties to control the appearance of these shapes. You can set the fill color of a mojs shape using the fill property. When no color is specified, the library will use the deeppink color to fill the shape. Similarly, you can specify the stroke color for a shape using the stroke property. When no stroke color is specified, mojs keeps the stroke transparent. You can control the fill and stroke opacity for a shape using the fillOpacity and strokeOpacity properties. They can have any value between 0 and 1.

Mojs allows you to control other stroke-related properties of a shape as well. For instance, you can specify the pattern of dashes and gaps in a stroke path using the strokeDasharray property. This property accepts both strings and numbers as valid values. Its default value is zero, which means that the stroke will be a solid line. The width of a stroke can be specified using the strokeWidth property. All the strokes will be 2px wide by default. The shape of different lines at their end points can be specified using the strokeLinecap property. Valid values for strokeLinecap are butt, round, and square.

Any shape that you create is placed at the center of its parent element by default. This is because the left and right properties for a shape are set to 50% each. You can change the values of these properties to place the elements in different locations. Another way to control the position of a shape is with the help of the x and y properties. They determine how much a shape should be shifted in the horizontal and vertical direction respectively.

You can specify the radius of a shape using the radius property. This value is used to determine the size of a particular shape. You can also use radiusX and radiusY to specify the size of a shape in a particular direction. Another way of controlling the size of a shape is with the help of the scale property. The default value of scale is 1, but you can set it to any other number you like. You can also scale a shape in a particular direction using the scaleX and scaleY properties.

The origin of all these transformations of a shape is its center by default. For example, if you rotate any shape by specifying a value for the angle property, the shape will rotate around its center. If you want to rotate a shape around some other point, you can specify it using the origin property. This property accepts a string as its value. Setting it to '0% 0%' will rotate, scale or translate the shape around its top left corner. Similarly, setting it to '50% 0%' will rotate, scale or translate the shape around the center of its top edge.

You can use all these properties we just discussed to create a large variety of shapes. Here are a few examples:

var circleA = new mojs.Shape({ parent: ".container", shape: "circle", left: 0, fill: "orange", stroke: "black", strokeWidth: 5, isShowStart: true }); var circleB = new mojs.Shape({ parent: ".container", shape: "circle", left: 175, fill: "orange", stroke: "red", radiusX: 80, strokeWidth: 25, strokeDasharray: 2, isShowStart: true }); var rectA = new mojs.Shape({ parent: ".container", shape: "rect", left: 350, fill: "red", stroke: "black", strokeWidth: 5, isShowStart: true }); var rectB = new mojs.Shape({ parent: ".container", shape: "rect", left: 500, fill: "blue", stroke: "blue", radiusX: 40, radiusY: 100, strokeWidth: 25, strokeDasharray: 20, isShowStart: true }); var polyA = new mojs.Shape({ parent: ".container", shape: "polygon", top: 300, left: 0, fill: "yellow", stroke: "black", strokeWidth: 10, points: 8, isShowStart: true }); var polyB = new mojs.Shape({ parent: ".container", shape: "polygon", top: 350, left: 175, radiusX: 100, radiusY: 100, fill: "violet", stroke: "black", strokeWidth: 6, strokeDasharray: "15, 10, 5, 10", strokeLinecap: "round", points: 3, isShowStart: true }); var lineA = new mojs.Shape({ parent: ".container", shape: "cross", top: 350, left: 375, stroke: "red", strokeWidth: 40, isShowStart: true }); var zigzagA = new mojs.Shape({ parent: ".container", shape: "zigzag", top: 500, left: 50, fill: "transparent", stroke: "black", strokeWidth: 4, radiusX: 100, points: 10, isShowStart: true }); var zigzagB = new mojs.Shape({ parent: ".container", shape: "zigzag", top: 500, left: 350, fill: "blue", stroke: "transparent", radiusX: 100, points: 50, isShowStart: true });

The shapes created by the above code are shown in the CodePen demo below:

Animating Shapes in Mojs

You can animate almost all the properties of a shape that we discussed in the previous section. For instance, you can animate the number of points in a polygon by specifying different initial and final values. You can also animate the origin of a shape from '50% 50%' to any other value like '75% 75%'. Other properties like angle and scale behave just like they did in the Html module. 

The duration, delay and speed of different animations can be controlled using the duration, delay and speed properties respectively. The repeat property also works like it did in the Html module. You can set it to 0 if you want to play the animation only once. Similarly, you can set it to 3 to play the animation 4 times. All the easing values that were valid for the Html module are also valid for the Shape module.

The only difference between the animation capabilities of these two modules is that you cannot specify the animation parameters individually for the properties in the Shape module. All the properties that you are animating will have the same duration, delay, repetitions, etc.

Here is an example where we animate the x position, scale and angle of a circle:

var circleA = new mojs.Shape({ parent: ".container", shape: "circle", left: 175, fill: "red", stroke: "black", strokeWidth: 100, strokeDasharray: 18, isShowStart: true, x: { 0: 300 }, angle: { 0: 360 }, scale: { 0.5: 1.5 }, duration: 1000, repeat: 10, isYoyo: true, easing: "quad.in" });

One way to control the playback of different animations is by using the .then() method to specify a new set of properties to be animated after the first animation sequence has fully completed. You can give all animation properties new initial and final values inside .then(). Here is an example:

var polyA = new mojs.Shape({ parent: ".container", shape: "polygon", fill: "red", stroke: "black", isShowStart: true, points: 4, left: 100, x: { 0: 500 }, strokeWidth: { 5: 2 }, duration: 2000, easing: 'elastic.in' }).then({ strokeWidth: 5, points: { 4: 3 }, angle: { 0: 720 }, scale: { 1: 2 }, fill: { 'red': 'yellow' }, duration: 1000, delay: 200, easing: 'elastic.out' });

Final Thoughts

In this tutorial, we learned how to create different shapes using mojs and how to animate the properties of these shapes. 

The Shape module has all the animation capabilities of the Html module. The only difference is that the properties cannot be animated individually. They can only be animated as a group. You can also control the animation playback by using different methods to play, pause, stop and resume the animations at any point. I covered these methods in detail in the first tutorial of the series.

If you have any questions related to this tutorial, feel free to post a comment. In the next tutorial, you will learn about the ShapeSwirl and stagger modules in mojs.

Categories: Web Design

Getting Started With the Mojs Animation Library: The HTML Module

Wed, 04/11/2018 - 05:00

A lot of websites now use some sort of animation to make their landing pages more appealing. Thankfully, there are many libraries which allow you to animate elements on a webpage without doing everything from scratch. In this tutorial, you will learn about one such library called mojs.

The library is very easy to use because of its simple declarative API. The animations that you can create with mojs will all be smooth and retina ready so that everything looks professional.

Installing Mojs

There are many ways to include mojs in your projects. You can grab the library from its GitHub repository. Alternatively, you can directly include a link to the latest version of the library from different CDNs in your project. 

<script src="//cdn.jsdelivr.net/mojs/latest/mo.min.js"></script>

Developers can also install mojs using package managers like npm and bower by running the following command:

npm install mo-js bower install mojs

Once you have included the library in your project, you can start using different modules to create interesting animations.

The HTML Module in Mojs

This tutorial will focus on the HTML module in the mojs library. This module can be used to animate different HTML elements on the webpage.

The first thing that you need to do in order to animate a DOM element is create a mojs Html object. You can specify the selector of an element and its properties that you want to animate inside this object.

Setting a value for el will let you identify the element which you want to animate using mojs. You can either set its value as a selector or a DOM node.

The HTML module has some predefined attributes which can be used to animate different transform-related properties of a DOM element. For example, you can control the translation animation of an element along the x, y and z axes by specifying start and end values for the x, y and z properties. You can also rotate any element along different axes by using the angleX, angleY and angleZ properties. This is similar to the corresponding rotateX(), rotateY() and rotateZ() transforms in CSS. You can also skew an element along the X or Y axis with the help of the skewX and skewY properties.

Applying scaling animations on different elements is just as easy. If you want to scale an element in both directions, simply set a value for the scale property. Similarly, you can animate the scaling of elements along different axes by setting appropriate values for the scaleX and scaleY properties.

Besides all these properties which let you set the initial and final values of the animation, there are some other properties which control the animation playback. You can specify the duration of the animation using the duration property. The provided value needs a number, and it will set the animation duration in milliseconds. If you want to start an animation after some delay, you can set the delay value using the delay property. Just like duration, delay also expects its value to be a number.

Animations can be repeated more than once with the help of the repeat property. Its default value is zero, which means that the animation would be played only once. Setting it to 1 will play the animation twice, and setting it to 2 will play the animation three times. Once the animation has completed its first iteration, the element will go back to its initial state and start animating again (if you have set a value for the repeat property). This sudden jump from the final state to initial state may not be desirable in all cases. 

If you want the animation to play backwards once it has reached the final state, you can set the value of the isYoyo property to true. It is set to false by default. Finally, you can set the speed at which the animation should be played using the speed property. Its default value is 1. Setting it to 2 will play the animation twice as fast. Similarly, setting it to 0.5 will play the animation at half the speed.

The mojs Html objects that you created will not animate the respective elements by themselves. You will have to call the play() method on each mojs Html animation that you want to play. Here is an example which animates three different boxes using all the properties we just discussed:

var htmlA = new mojs.Html({ el: ".a", x: { 0: 400 }, angleZ: { 0: 720 }, duration: 1000, repeat: 4, isYoyo: true }); var htmlB = new mojs.Html({ el: ".b", x: { 400: 0 }, angleY: { 0: 360 }, angleZ: { 0: 720 }, duration: 1000, repeat: 4 }); var htmlC = new mojs.Html({ el: ".c", x: { 0: 400 }, angleY: { 0: 360 }, scaleZ: { 1: 2 }, skewX: { 0: 30 }, duration: 1000, repeat: 4, isYoyo: true }); document.querySelector(".play").addEventListener("click", function() { htmlA.play(); htmlB.play(); htmlC.play(); });

You are not limited to just animating the transform properties of an element. The mojs animation library allows you to animate all other animatable CSS properties as well. You just have to make sure that you provide valid initial and final values for them. For instance, you can animate the background color of an element by specifying valid values for background. 

If the CSS property that you want to animate contains a hyphen, you can remove the hyphen and convert the property name to camelCase when setting initial and final values inside the mojs Html object. This means that you can animate the border-radius by setting a valid value for the borderRadius property. The following example should make everything clear:

var htmlA = new mojs.Html({ el: ".a", x: { 0: 400 }, angleZ: { 0: 360 }, background: { red: 'black' }, borderWidth: { 10: 20 }, borderColor: { 'black': 'red' }, borderRadius: { 0: '50%' }, duration: 2000, repeat: 4, isYoyo: true }); document.querySelector(".play").addEventListener("click", function() { htmlA.play(); });

In the above example, the border color changes from black to red while the border radius animates from 0 to 50%. You should note that a unitless number will be considered a pixel value, while a number with units should be specified as a string like '50%'.

So far we have used a single set of tween properties to control the playback of different animations. This meant that an element would take the same time to move from x:0 to x:200 as it will take to scale from scale:1 to scale:2. 

This may not be a desirable behavior as you might want to delay the animation of some properties and control their duration as well. In such cases, you can specify the animation playback parameters of each property inside the property object itself.

var htmlA = new mojs.Html({ el: ".a", x: { 0: 400, duration: 1000, repeat: 8, isYoyo: true }, angleY: { 0: 360, delay: 500, duration: 1000, repeat: 4, isYoyo: true }, angleZ: { 0: 720, delay: 1000, duration: 1000, repeat: 4, isYoyo: true } }); document.querySelector(".play").addEventListener("click", function() { htmlA.play(); });

Easing Functions Available in Mojs

Every animation that you create will have the sin.out easing applied to it by default. If you want the animation playback to progress using a different easing function, you can specify its value using the easing property. By default, the value specified for easing is also used when the animation is playing backwards. If you want to apply a different easing for backward animations, you can set a value for the backwardEasing property.

The mojs library has 11 different built-in easing functions. These are linear, ease, sin, quad, cubic, quart, quint, expo, circ, back, and elastic. The linear easing only has one variation named linear.none. This makes sense because the animation will progress with the same speed at different stages. All other easing functions have three different variations with in, out and inout appended at the end.

There are two methods to specify the easing function for an animation. You can either use a string like elastic.in or you can access the easing functions directly using the mojs.easing object like mojs.easing.elastic.inout. In the embedded CodePen demo, I have applied different easing functions on each bar so its width will change at a different pace. This will give you an idea of how the animation speed differs with each easing.

var allBoxes = document.querySelectorAll(".box"); var animations = new Array(); var easings = ['ease.in', 'sin.in', 'quad.in', 'cubic.in', 'quart.in', 'quint.in', 'expo.in', 'circ.in', 'back.in', 'elastic.in']; allBoxes.forEach(function(box, index) { var animation = new mojs.Html({ el: box, width: { 0: 550, duration: 4000, repeat: 8, isYoyo: true, easing: easings[index] } }); animations.push(animation); }); document.querySelector(".play").addEventListener("click", function() { animations.forEach(function(anim) { anim.play(); }); });

Since we only want to change the easing function applied to each box, I have created a loop to iterate over them and then apply an easing function picked up from the easings array. This prevents unnecessary code duplication. You can use the same technique to animate multiple elements where the property values vary based on a pattern.

Controlling Animation Playback

Mojs provides a lot of methods which allow us to control the animation playback for different elements once it has already started. You can pause the animation at any time by calling the pause() method. Similarly, you can resume any paused animation by calling the resume() method. 

Animations that have been paused using pause() will always resume from the point at which you called pause(). If you want the animation to start from the beginning after it has been paused, you should use the stop() method instead.

You can also play the animation backwards using the playBackward() method. Earlier, we used the speed property to control the speed at which mojs played an animation. Mojs also has a setSpeed() method which can set the animation speed while it is still in progress. In the following example, I have used all these methods to control the animation playback based on button clicks.

var speed = 1; var htmlA = new mojs.Html({ el: ".a", angleZ: { 0: 720 }, borderRadius: { 0: '50%' }, borderWidth: { 10: 100 }, duration: 2000, repeat: 9999, isYoyo: true }); document.querySelector(".play").addEventListener("click", function() { htmlA.play(); }); document.querySelector(".pause").addEventListener("click", function() { htmlA.pause(); }); document.querySelector(".stop").addEventListener("click", function() { htmlA.stop(); }); document.querySelector(".faster").addEventListener("click", function() { speed = speed + 1; htmlA.setSpeed(speed); document.querySelector(".data").innerHTML = "Speed: " + speed; }); document.querySelector(".slower").addEventListener("click", function() { speed = speed/2; htmlA.setSpeed(speed); document.querySelector(".data").innerHTML = "Speed: " + speed; });

In the following demo, the current animation playback speed is shown in the black box in the bottom left corner. Clicking on Faster will increase the current speed by 1, and clicking on Slower will halve the current speed.

Final Thoughts

In this tutorial, we learned how to animate different DOM elements on a webpage using the HTML module in mojs. We can specify the element we want to animate using either a selector or a DOM node. The library allows you to animate different transform properties and the opacity of any element using the built-in properties of the mojs Html object. However, you can also animate other CSS properties by specifying the name using camelCase notation.

JavaScript is not without its learning curves, and there are plenty of frameworks and libraries to keep you busy, as well. If you’re looking for additional resources to study or to use in your work, check out what we have available in the Envato Market.

Let me know if there is anything you would like me to clarify in this tutorial. We will cover the Shape module from the mojs library in the next tutorial.

Categories: Web Design

Project Management Considerations for Your WordPress Project

Mon, 04/09/2018 - 05:00

Lean, Agile, Waterfall; there are dozens of project management methodologies out there, and each one works to abstract your project into a common series of tasks and formulas. 

When it comes to software engineering, this can become complicated. For instance, it can cause issues between developers and managers whose organization styles differ. The manager needs that layer of abstraction to keep track of necessary metrics. The developer, however, can suffer from continual small task fatigue and feelings of being micromanaged.

Regardless of the programming language, framework, or libraries, none of them will perfectly fit into the variety of project management methodologies that exist. So how do we improve processes?

By categorizing the differences between tools. Let’s dig into the distinct features that comprise WordPress, and how they can impact the perspectives of managers and developers.

How to Adapt Your Project Management System to WordPress

To adapt our system, we first have to understand the nuances of WordPress. Of course, we don’t need to take every coding standard or functionality difference into account, but we do need to refer to significant sections that may make a difference. We’ll group these into three categories:

  • Challenges: Any piece that needs to be planned around when defining tasks, milestones, and implementations for the project.

  • Risks: Large issues that should be hedged against when possible. These are likely weaknesses in the framework that may push back development if they come to fruition.

  • Opportunities: Unique benefits in the framework that may provide additional features, make development more efficient, or in some way provide a competitive or internal advantage.

The difficulty with identifying these sections is that while they can mostly be learned through research and preparation, many are simply experienced during the attempt. In addition, defining them requires critical evaluation from both developers and managers, which may not always occur.

To adapt your current project management system to WordPress, let’s take a look at the unique Challenges, Risks, and Opportunities that are commonly faced.

Unique Challenges of Using WordPress

Every Content Management System by nature has its own set of downsides. With the involvement of different parties possessing different goals, compromises are bound to happen. Whether it’s users sacrificing customization or developers losing maintenance ease, something has to give. Here are some of the challenges using WordPress presents:

Using an Open-Source Base

Having an open-source base brings with it a bevy of pros and cons. As far as the challenges that are brought on by this, here are the most important:

Code-Base Maintenance

WordPress’s open-source base means that you’ll benefit from regular improvements to the system, but have very little control over those improvements. If a particular bug or feature change is an issue with your build, there is no guarantee of when it will be dealt with. Of course, you can always contribute to the base itself to speed things along, but with so many users, your addition may not be approved. After all, what you have in mind may not be the best solution for most users.

Dealing With Updates

To combat this, you can modify your own codebase or extend it as necessary, but this creates a new set of challenges. If you’ve created a workaround, you will need to be aware of changes to the central codebase that may alter or correct your solution in the future. If you’ve modified the codebase, you will need to be aware that updating WordPress core may alter the functionality that you’ve built, and plan accordingly.

Building Non-Generalist Sites

Because of the sheer number of websites that rely on WordPress, it’s likely that there will come a time when your site and the future of WordPress might be at odds. This becomes more true as your site moves away from what a typical WordPress site might look like.

To counteract this, try to work within WordPress’s constraints as much as possible, to minimize any issues that might arise from future updates. If while planning your project a large portion seems to be fighting the core rather than benefiting from it, consider using another CMS. Otherwise, you can also advise clients against updating WordPress after the project launches, though that brings with it a new set of challenges.

“Piecemeal” Development

The last major challenge to be aware of is the separation of components within WordPress. The divided structure of plugins, themes, and core can be a great tool for planning and hierarchy, but introduces additional third-party software.

Plugins and themes that are being used, but have not been created in-house, should receive an extra level of care. Take the time to do a proper discovery of these components to deal with possible complications.

Unique Risks of Using WordPress

Risks are a level beyond challenges, typically indicating issues that could be catastrophic to a project or whose solutions rest outside of development itself. Take a look at the two biggest that I’ve run into:

Security Issues

With code coming from multiple sources, it’s inevitable that sometimes a bug or exploit will come to light that might leave your project vulnerable. While these issues are typically fixed within days of exposure, the time in-between can be especially hazardous.

Because of the large number of sites using WordPress, exploits become well known quickly and can potentially be utilized en masse. Making sure that your project uses a variety of security measures can help to reduce the risk during those couple of days, but sometimes the only solution is to wait for a patch.

Inclusion of Third-Party Projects

Plugins are one of the most important features for many WordPress users. On the development side, however, plugins introduce unknown elements. Since they can be upgraded separately from the rest of the system (and potentially by your client), utilizing plugins as a key component in your project could be problematic later on.

Additionally, plugins need to be properly vetted before inclusion, otherwise you risk the potential of including dangerous code within your project.

Unique Benefits of Using WordPress

WordPress may have its own risks and challenges, but it has plenty of benefits as well. After all, it’s the most popular CMS on the web for a reason. Here are the pros to the cons above:

Using an Open-Source Base

We talked about the downsides of an open-source base, but there are many upsides as well. Using WordPress is free, and it boasts a wide range of documentation as well as extensive tutorials around the internet. This means that developers can quickly get up to speed on your project, and expanding your team’s knowledge during a project isn’t as arduous a task.

The other major benefit of the open-source base is the multitudes of people that work together to make it happen. A team of a handful of individuals could make something similar, but it’s unlikely to happen at the same pace and quality as WordPress.

Having many varied developers contributing to the code, paired with structured reviews, means that your projects are built on a solid, quality source. Having a large number of contributors also speeds along production, allowing features to be added quickly and patches to be issued in limited timeframes.

Robust Third-Party Solution Availability

WordPress boasts an extensive array of plugins, themes, and code snippets that can help streamline the production process. By utilizing these third-party solutions, you can quickly prototype—and even implement—entirely finished components into your project, offering additional features and efficiency.

Even if a plugin doesn’t quite do what you want, the most popular ones adhere to WordPress coding standards, making them easily adaptable to your needs.

Compartmentalized Design

A predefined and well-structured hierarchy and template system can help projects start off in an organized way. Instead of spending time deciding on engineering structures, WordPress allows efficient work within a well-established system. In addition, it’s suitable for most project management systems and allows for multiple pieces of the project to be developed simultaneously.

This compartmentalized design also makes it easy to determine where issues originate, and to maintain code throughout a project’s iterations.

Aligning Team Perspectives

Taking a Content Management System like WordPress and breaking it down into how managers and developers perceive it can streamline communication overall. Integrating these perspectives in your project management style should alleviate some anxiety with your developers. It gives them the benefit of the doubt, while adding some much-needed understanding to the team.

If you're looking for other utilities to help you build out your growing set of tools for WordPress or for code to study and become more well-versed in WordPress, don't forget to see what we have available in Envato Market.

Did I miss any key parts of WordPress that project managers should be aware of? Let me know in the comments!

Categories: Web Design

Introduction to the CSS Grid Layout With Examples

Fri, 04/06/2018 - 05:00
What You'll Be Creating

In this tutorial, I will cover the basics of the CSS grid layout with example scenarios. CSS Grid is supported by almost all modern browsers now, and it is ready to be used in production. Unlike other layout methods such as flexbox, the grid layout gives you two degrees of freedom, which makes it so versatile that positioning the elements is just a breeze.

HTML Structure for the CSS Grid Layout

In order to use the CSS Grid layout, your HTML elements should have a specific structure.

You need to wrap the elements that you want to control within a parent container DIV.

<div class="wrapper"> <div class="div1">1</div> <div class="div2">2</div> <div class="div3">3</div> <div class="div4">4</div> </div>

Let's add some styling for our DIVs so that we can distinguish them easily.

Also, set the display: grid in your wrapper DIV so that we can start using the grid layout.

.wrapper > div{ background-color: orange; border: 1px black solid; } .wrapper > div:nth-child(odd){ background-color: indianred; } .wrapper{ display: grid }

From this point on, all the styling will go into the wrapper DIV. If we ever want to control the child DIVs at any point, then we will be adding grid-specific styling rules for the specific child DIV.

Rules on Parent DIV

The first things we need to learn about the grid layout are grid-template-columns and grid-template-rows. Those two rules basically control how your grid is shaped.

The value of these rules can be a length, a percentage, or a fraction of the free space in the grid. You can also set any value to auto, which fills up the remaining space.

Let's see some examples below.

Grid-template-columns & Grid-template-rowsgrid-template-columns.wrapper{ display: grid; grid-template-columns: 100px 100px 100px }.wrapper{ display: grid; grid-template-columns: 100px auto 100px }.wrapper { display: grid; grid-template-columns: 1fr 1fr 1fr 1fr; }grid-template-columns & grid-template-rows

Let's start building a real grid, in which we have control over both columns and rows.

.wrapper { display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: 50px 50px; }.wrapper { display: grid; grid-template-columns: 100px 20px 250px; grid-template-rows: 150px 40px; }

Here I just added two more child DIVs to the HTML for the same CSS.

Repeat a grid-template Pattern

If you have a repeating pattern for grid-template, you can just use repeat and tell it how many times to repeat the same pattern.

For instance, say you have 12 elements, and you want to lay them out horizontally with equal width. You could repeat 1fr 12 times inside grid-template-columns, which is not effective. So, instead, you can use repeat(12, 1fr).

.wrapper { display: grid; grid-template-columns: repeat(12, 1fr) }

Likewise, you can repeat a pattern.

.wrapper { display: grid; grid-template-columns: repeat(4, 1fr 5fr 10fr); }Grid-auto-columns & Grid-auto-rows

This rule helps you to set the width and height of grid cells.

If you don't set this rule, your grid rows and columns will expand with the content.

.wrapper { display: grid; grid-template-columns: repeat(4, 1fr); grid-auto-rows: 100px; }.wrapper { display: grid; grid-template-columns: repeat(4, 1fr); grid-auto-rows: 20px 80px; }

One nice feature to use with grid-auto rule is the minmax function.

You simply set the minimum size as the first parameter and the maximum as the second parameter. If you set auto for the second parameter, you get a responsive cell size.

.wrapper { display: grid; grid-template-columns: repeat(4, 1fr); grid-auto-rows: minmax(50px, auto) }

Below you see two different DIV contents with the same CSS rules.

Grid-gap

As the name implies, this rule creates a gap between grid cells.

If you use grid-gap: 5px, you get a 5px gap between each cell. Alternatively, you can only set the row or column gaps, with grid-row-gap: 5px and grid-column-gap: 5px respectively.

.wrapper { display: grid; grid-template-columns: repeat(4, 1fr); grid-auto-rows: minmax(50px, auto); grid-gap: 5px; }Rules on Child DIVs

So far, we've only focused on the shape of the grid and items just flowed in the grid. Now we will learn how to control each item individually.

In order to position the items, we use grid lines as a reference. Below you see the row and column lines in black and orange respectively for a 2x4 grid.

We will use the grid-column and grid-row rules with line numbers to position the elements.

For example, if we set grid-column: 1/3 for the first child div, it will use the first two cells in the grid. 

Consider the HTML and CSS below:

<div class="wrapper"> <div class="div1">1</div> <div class="div2">2</div> <div class="div3">3</div> <div class="div4">4</div> <div class="div5">5</div> <div class="div6">6</div> <div class="div7">7</div> <div class="div8">8</div> </div>.wrapper { display: grid; grid-template-columns: repeat(4, 1fr); grid-auto-rows: 100px; grid-gap: 5px; }

We have four equally sized columns and eight elements in the wrapper DIV.

.div1{ grid-column: 1/3; } .div1{ grid-column: 1/3; grid-row: 1/3; }

You can also combine these two rules into a single rule, grid-area: rowStart/columnStart/rowEnd/columnEnd.

.div1{ grid-area: 2/2/3/4; }

As illustrated in the above example, elements are not bound to the HTML structure. Notice how the first element is repositioned with the grid-area rule.

Grid-area & grid-template-areas

You can name each child element and use these names to create your grid. This is really powerful, and it makes doing layout more intuitive.

So we define a DIV for each element we are planning to place in our grid system.

I am planning to have a header, leftColumn, rightColumn, middleTop, middleBottom, and a footer.

So in my HTML I need that many child DIVs. The class names can be anything.

<div class="wrapper"> <div class="header">Header</div> <div class="leftCol">LeftCol</div> <div class="rightCol">RightCol</div> <div class="midTop">midTop</div> <div class="midBottom">midBottom</div> <div class="footer">Footer</div> </div>

Then, inside my CSS, I set the grid-area names. Those names can be anything; they are not supposed to match the class names.

.header{ grid-area: header; background-color: LightSeaGreen ; } .leftCol{ grid-area: leftCol; background-color: orange; } .rightCol{ grid-area: rightCol; background-color: lightblue; } .midTop{ grid-area: midTop; background-color: lightgrey; } .midBottom{ grid-area: midBottom; background-color: pink; } .footer{ grid-area: footer; background-color: lightgreen; }

Then, inside my wrapper DIV, I use the grid-template-areas rule to lay out those elements by referring to their defined names.

Notice that I have a 4x4 grid.

.wrapper { display: grid; grid-template-columns: 1fr 4fr 4fr 1fr; grid-template-rows: 50px 100px 100px 30px; grid-template-areas: "header header header header" "leftCol midTop midTop rightCol" "leftCol midBottom midBottom rightCol" "footer footer footer footer"; grid-gap: 5px; }

If, for example, I want the footer to take only two columns and be centered, then I simply replace the first and the last appearance of footer with a dot (.) in grid-template-areas.

.wrapper { display: grid; grid-template-columns: 1fr 4fr 4fr 1fr; grid-template-rows: 50px 100px 100px 30px; grid-template-areas: "header header header header" "leftCol midTop midTop rightCol" "leftCol midBottom midBottom rightCol" ". footer footer ."; grid-gap: 5px; }Conclusion

CSS Grid has tons of rules, and I only covered the most useful ones in this tutorial. You can still dig into MDN Web Docs or any other sources for the full list of grid properties and functions.

Categories: Web Design

Pages