Getting undefined from jquery find() in my example

I have an HTML page like this :

I have an HTML page like this :

I have put an event on input.global_filter using jquery as follows:

$('input.global_filter').on('keyup click', function() {
  document.write($(this).find('.example:first').prop('tagName'));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<!-- Table3-->
<table class="example" data-column="3">
......
</table>

<table>
<tbody>
<tr>
<td>
<input type="text" class="global_filter">
</td>
</tr>
</tbody>
</table>

<!-- Table1-->
<table class="example" data-column="1">
......
</table>

<!-- Table2-->
<table class="example" data-column="2">
......
</table>


This results in undefined. It should give the result TABLE. Where am I wrong ?

Is there a possible that I can transfer a certain html tag to another position using jquery?

I have here a navigation bar with a caret beside it. And I wanted to change this one dynamically using jquery. When on click, the activated menu transfers to the one being clicked. What I wanted to happen is I want to move also the arrow to the clicked menu in the navigation bar. How do I do that in jquery?

I have here a navigation bar with a caret beside it. And I wanted to change this one dynamically using jquery. When on click, the activated menu transfers to the one being clicked. What I wanted to happen is I want to move also the arrow to the clicked menu in the navigation bar. How do I do that in jquery?

                         <div class = "side-nav-bar content">
                            <a class="active-menu" href="javascript:;">체육학</a><i class="arrow right"></i>
                            <a href="javascript:;">전공소개</a>
                            <a href="javascript:;">졸업 후 진로</a>
                            <a href="javascript:;">교육 프로그램</a>
                            <a href="javascript:;">교수소개</a>
                    </div>
                      $('.side-nav-bar a').click(function(){
        $('.side-nav-bar a').not(this).removeClass('active-menu');
        $(this).addClass('active-menu');
        $('arrow').insertAfter('active-menu');
}); 

                      .arrow {
                    border: solid white;
                    border-width: 0 2px 2px 0;
                    display: inline-flex;
                    padding: 3px;
                    position: absolute;
                    top: 23px;
                    right: 10px;
                     }

                      .right {
                        transform: rotate(-45deg);
                        -webkit-transform: rotate(-45deg);
                        }


Building a minesweeper game using Javascript, HTML and CSS

Building a minesweeper game using Javascript, HTML and CSS

In this article, you'll learn how to build minesweeper using JavaScript, HTML and CSS. I also used jQuery, a JavaScript library that is helpful for interacting with html. Whenever you see a function call with a leading dollar sign, that is jQuery at work

In this article, you'll learn how to build minesweeper using JavaScript, HTML and CSS. I also used jQuery, a JavaScript library that is helpful for interacting with html. Whenever you see a function call with a leading dollar sign, that is jQuery at work

If you want to learn how to build minesweeper with JavaScript, the first step is understanding how the game works. Let’s jump right in and talk about the rules.

Rules of the Game
  1. The minesweeper board is a 10 x 10 square. We could make it other sizes, like the classic Windows version, but for demonstration purposes we will stick to the smaller, “beginner” version of the game.
  2. The board has a predetermined number of randomly placed mines. The player cannot see them.
  3. Cells can exist in one of two states: opened or closed. Clicking on a cell opens it. If a mine was lurking there, the game ends in failure. If there is no mine in the cell, but there are mines in one or more of its neighboring cells, then the opened cell shows the neighboring mine count. When none of the cell’s neighbors are mined, each one of those cells is opened automatically.
  4. Right clicking on a cell marks it with a flag. The flag indicates that the player knows there is a mine lurking there.
  5. Holding down the ctrl button while clicking on an opened cell has some slightly complicated rules. If the number of flags surrounding the cell match its neighbor mine count, and each flagged cell actually contains a mine, then all closed, unflagged neighboring cells are opened automatically. However, if even one of these flags was placed on the wrong cell, the game ends in failure.
  6. The player wins the game if he/she opens all cells without mines.
Data Structures

Cell

JavaScript code representing a minesweeper cell.

Each cell is an object that has several properties:

  • id: A string containing the row and column. This unique identifier makes it easier to find cells quickly when needed. If you pay close attention you will notice that there are some shortcuts I take related to the ids. I can get away with these shortcuts because of the small board size, but these techniques will not scale to larger boards. See if you can spot them. If you do, point them out in the comments!
  • row: An integer representing the horizontal position of the cell within the board.
  • column: An integer representing the vertical position of the cell within the board.
  • opened: This is a boolean property indicating whether the cell has been opened.
  • flagged: Another boolean property indicating whether a flag has been placed on the cell.
  • mined: Yet another boolean property indicating whether the cell has been mined.
  • neighborMineCount: An integer indicating the number of neighboring cells containing a mine.

Board

JavaScript code representing our game board.

Our board is a collection of cells. We could represent our board in many different ways. I chose to represent it as an object with key value pairs. As we saw earlier, each cell has an id. The board is just a mapping between these unique keys and their corresponding cells.

After creating the board we have to do two more tasks: randomly assign the mines and calculate the neighboring mine counts. We’ll talk more about these tasks in the next section.

Algorithms

Randomly Assign Mines

JavaScript code for randomly assigning mines to cells.

One of the first things we have to do before a game of minesweeper can be played is assign mines to cells. For this, I created a function that takes the board and the desired mine count as parameters.

For every mine we place, we must generate a random row and column. Furthermore, the same row and column combination should never appear more than once. Otherwise we would end up with less than our desired number of mines. We must repeat the random number generation if a duplicate appears.

As each random cell coordinate is generated we set the *mined *property to true of the corresponding cell in our board.

I created a helper function in order to help with the task of generating random numbers within our desired range. See below:

Helper function for generating random integers.

Calculate Neighbor Mine Count

JavaScript code for calculating the neighboring mine count of each cell.

Now let’s look at what it takes to calculate the neighboring mine count of each cell in our board.

You’ll notice that we start by looping through each row and column on the board, a very common pattern. This will allow us to execute the same code on each of our cells.

We first check if each cell is mined. If it is, there is no need to check the neighboring mine count. After all, if the player clicks on it he/she will lose the game!

If the cell is not mined then we need to see how many mines are surrounding it. The first thing we do is call our **getNeighbors **helper function, which returns a list of ids of the neighboring cells. Then we loop through this list, add up the number of mines, and update the cell’s *neighborMineCount *property appropriately.

Won’t you be my neighbor?

Let’s take a closer look at that **getNeighbors **function, as it will be used several more times throughout the code. I mentioned earlier that some of my design choices won’t scale to larger board sizes. Now would be a good time to try and spot them.

JavaScript code for getting all of the neighboring ids of a minesweeper cell.

The function takes a cell id as a parameter. Then we immediately split it into two pieces so that we have variables for the row and the column. We use the **parseInt **function, which is built into the JavaScript language, to turn these variables into integers. Now we can perform math operations on them.

Next, we use the row and column to calculate potential ids of each neighboring cell and push them onto a list. Our list should have eight ids in it before cleaning it up to handle special scenarios.

A minesweeper cell and its neighbors.

While this is fine for the general case, there are some special cases we have to worry about. Namely, cells along the borders of our game board. These cells will have less than eight neighbors.

In order to take care of this, we loop through our list of neighbor ids and remove any id that is greater than 2 in length. All invalid neighbors will either be -1 or 10, so this little check solves the problem nicely.

We also have to decrement our index variable whenever we remove an id from our list in order to keep it in sync.

Is it mined?

Okay, we have one last function to talk about in this section: isMined.

JavaScript function that checks if a cell is mined.

The **isMined **function is pretty simple. It just checks if the cell is mined or not. The function returns a 1 if it is mined, and a 0 if it is not mined. This feature allows us to sum up the function’s return values as we call it repeatedly in the loop.

That wraps up the algorithms for getting our minesweeper game board set up. Let’s move on to the actual game play.

Opening A Cell

JavaScript code that executes when a minesweeper cell is opened.

Alright let’s dive right into this bad boy. We execute this function whenever a player clicks on a cell. It does a lot of work, and it also uses something called recursion. If you are unfamiliar with the concept, see the definition below:

Recursion: See recursion.

Ah, computer science jokes. They always go over so well at bars and coffee shops. You really ought to try them out on that cutie you’ve been crushing on.

Anyways, a recursive function is just a function that calls itself. Sounds like a stack overflow waiting to happen, right? That’s why you need a base case that returns a value without making any subsequent recursive calls.

Our function will eventually stop calling itself because there will be no more cells that need to be opened. We could have written this code without recursion, but I thought you all might want to see an example of it in action.

Handle Click Explained

The **handleClick **function takes a cell id as a parameter. We need to handle the case where the player pressed the ctrl button while clicking on the cell, but we will talk about that in a later section.

Assuming the game isn’t over and we are handling a basic left click event, there are a few checks we need to make. We want to ignore the click if the player already opened or flagged the cell. It would be frustrating for the player if an inaccurate click on an already flagged cell ended the game.

If neither of those are true then we will proceed. If a mine is present in the cell we need to initiate the game over logic and display the exploded mine in red. Otherwise, we will open the cell.

If the opened cell has mines surrounding it we will display the neighboring mine count to the player in the appropriate font color. If there are no mines surrounding the cell, then it is time for our recursion to kick in. After setting the background color of the cell to a slightly darker shade of gray, we call **handleClick **on each unopened neighboring cell without a flag.

Helper Functions

Let’s take a look at the helper functions we are using inside the **handleClick **function. We’ve already talked about getNeighbors, so we’ll skip that one. Let’s start with the **loss **function.

JavaScript code that gets called whenever the player has lost the game.

When a loss occurs, we set the variable that tracks this and then display a message letting the player know that the game is over. We also loop through each cell and display the mine locations. Then we stop the clock.

Second, we have the **getNumberColor **function. This function is responsible for giving us the color corresponding to the neighboring mine count.

JavaScript code that gets passed a number and returns a color.

I tried to match up the colors just like the classic Windows version of minesweeper does it. Maybe I should have used a switch statement, but I already took the screen shot, and it’s not really a big deal. Let’s move on to what the code looks like for putting a flag on a cell.

Flagging A Cell

JavaScript code for putting a flag on a minesweeper cell.

Right clicking on a cell will place a flag on it. If the player right clicks on an empty cell and we have more mines that need to be flagged we will display the red flag on the cell, update its flagged property to true, and decrement the number of mines remaining. We do the opposite if the cell already had a flag. Finally, we update the GUI to display the number of mines remaining.

Opening Neighboring Cells

JavaScript code for handling ctrl + left click

We have covered the actions of opening cells and marking them with flags, so let’s talk about the last action a player can take: opening an already opened cell’s neighboring cells. The **handleCtrlClick **function contains the logic for this. This player can perform this action by holding ctrl and left clicking on an opened cell that contains neighboring mines.

The first thing we do after checking those conditions is build up a list of the neighboring flagged cells. If the number of flagged cells matches the actual number of surrounding mines then we can proceed. Otherwise, we do nothing and exit the function.

If we were able to proceed, the next thing we do is check if any of the flagged cells did not contain a mine. If this is true, we know that the player predicted the mine locations incorrectly, and clicking on all of the non-flagged, neighboring cells will end in a loss. We will need to set the local *lost *variable and call the **loss **function. We talked about the **loss **function earlier in the article.

If the player did not lose, then we will need to open up the non-flagged neighboring cells. We simply need to loop through them and call the **handleClick **function on each. However, we must first set the *ctrlIsPressed *variable to false to prevent falling into the **handleCtrlClick **function by mistake.

Starting A New Game

We are almost done analyzing all of the JavaScript necessary to build minesweeper! All that we have left to cover are the initialization steps necessary for starting a new game.

JavaScript code for initializing minesweeper

The first thing we do is initialize a few variables. We need some constants for storing the html codes for the flag and mine icons. We also need some constants for storing the board size, the number of mines, the timer value, and the number of mines remaining.

Additionally, we need a variable for storing if the player is pushing the ctrl button. We utilize jQuery to add the event handlers to the document, and these handlers are responsible for setting the *ctrlIsPressed *variable.

Finally, we call the **newGame **function and also bind this function to the new game button.

Helper Functions

JavaScript code for starting a new game of minesweeper.

Th **newGame **function is responsible for resetting our variables so that our game is in a ready-to-play state. This includes resetting the values that are displayed to the player, calling initializeCells, and creating a new random board. It also includes resetting the clock, which gets updated every second.

Let’s wrap things up by looking at initializeCells.

JavaScript code for attaching click handlers to cells and checking for the victory condition.

The main purpose of this function is to add additional properties to our html game cells. Each cell needs the appropriate id added so that we can access it easily from the game logic. Every cell also needs a background image applied for stylistic reasons.

We also need to attach a click handler to every cell so that we can detect left and right clicks.

The function that handles left clicks calls handleClick, passing in the appropriate id. Then it checks to see if every cell without a mine has been opened. If this is true then the player has won the game and we can congratulate him/her appropriately.

The function that handles right clicks calls handleRightClick, passing in the appropriate id. Then it simply returns false. This causes the context menu not to pop up, which is the default behavior of a right click on a web page. You wouldn’t want to do this sort of thing for a standard business CRUD application, but for minesweeper it is appropriate.

Conclusion

Congrats on learning how to build minesweeper with JavaScript! That was a lot of code, but hopefully it makes sense after breaking it up into modules like this. We could definitely make more improvements to this program’s reusability, extensibility, and readability. We also did not cover the HTML or CSS in detail. If you have questions or see ways to improve the code, I’d love to hear from you in the comments!

Making the Move from jQuery to Vue

Making the Move from jQuery to Vue

This guide is more for people who may be coming from years of jQuery experience and want to see how things can be done with Vue. With that in mind, I'm going to focus on what I consider "core" jQuery use cases.

As someone who has used jQuery for many. years and has recently become a Vue convert, I thought it would be an interesting topic to discuss the migration process of working with one to the other.

Before I begin though, I want to ensure one thing is crystal clear. I am not, in any way whatsoever, telling anyone to stop using jQuery. That's been pretty fashionable lately, and heck, I wrote up something similar myself a few year ago ("How I'm (Not) Using jQuery"). If you get things done with jQuery and your end users are successfully using your site, then more power to you. Keep using what works for you.

This guide is more for people who may be coming from years of jQuery experience and want to see how things can be done with Vue. With that in mind, I'm going to focus on what I consider "core" jQuery use cases. I won't cover every single possible feature but instead take a "I often did [X] with jQuery" approach that may be more relatable to people considering learning Vue. (As an aside, also note that how I write my examples are simply one way of performing a task. Both jQuery and Vue give provide multiple ways to accomplish the same goal and that's a great thing!)

With that in mind, let's consider some high level things we might turn to jQuery for:

  • Finding something in the DOM (with the idea of doing something with it later)
  • Changing something in the DOM (e.g. the text of a paragraph or the class of a button)
  • Reading and setting form values
  • Form validation (which is really just a combination of the items above)
  • Ajax calls and handling the results
  • Event handling (e.g. on button click, do something)
  • Measuring or changing the styles of an element

There's more to jQuery, of course, but these uses (at least in my opinion), cover the most common use cases. Also note there's a lot of cross pollination in the list above. So, should we start with a simple one-to-one comparison of each? Nope, not so fast. Let's begin by covering the major difference in Vue applications.

Defining where Vue "works"

When we drop jQuery onto a page, we are basically adding a Swiss Army knife to JavaScript code to handle common web development tasks. We can do any of the uses case we’re going to cover in whatever order we see fit. For example, a client may ask for form validation today, then in a month or so, ask to do an Ajax-based search form in the header of the site.

Vue has one significant difference in that respect. When starting a with Vue project, we start by defining an "area" in the DOM we want it to focus on. So, let’s consider a simple prototype web page:

HTML

<body>

  <header>
    Fancy header stuff here
  </header>

  <div id="sidebar">
    Some sidebar doohicky here
  </div>

  <main>
    <p>
      Main site content here, super important stuff...
    </p>
    <div id="loginForm">
      A login form of course
    </div>
  </main>

</body>

In a typical jQuery application, we may write code to work with the header, sidebar, and login form or something. No big whoop:

Javascript

$(document).ready(function() {

  $('header') // something...

  $('#sidebar') // something...

  $('#loginForm') // something... 

});

In a Vue application, we first specify what are we're working with. Imagine our client first asked to add validation to the loginForm element. Our Vue code would specify that:

Javascript

new Vue({
  el: '#loginForm',
  // Code here...
});

This means that we’d typically end up adding a second Vue application if the client later decides to have us add something to the sidebar:

Javascript

new Vue({
  el:'#loginForm',
  // Code here...
});

new Vue({
  el:'#sideBar',
  // Code here...
});

Is that a bad thing? Absolutely not. Right away, we get the benefit of encapsulation. If we accidentally use a variable with a generic name (we've all done that), we don't have to worry about conflicts with other parts of your code. Later on when the client adds yet another request, having our unique, logical sets of Vue code separated out like this gives us some great peace of mind that things won't step on each other.

So, yes, a good thing. But it absolutely caused me to stop a bit when I first began using Vue. Now, onto our use cases.

Finding Stuff in the DOM

Another aspect you'll find interesting, or scary, is how to "find stuff in the DOM." That's a bit vague, but let's consider a firm example. We have a button, and when it’s clicked, we make something happen. Here's an abbreviated example of how this could look:

HTML

<button id="myButton">Click Me!</button>
<!-- More stuff... -->
<script>
$(document).ready(function() {

  $('#myButton').click(function() {
    alert(1);
  });

});
</script>

Now let's compare that to how it can be done with Vue:

HTML

<div id="app">
  <button v-on:click="doSomething">Click Me!</button>
</div>

<script>
const app = new Vue({
  el:'#app',
  methods: {
    doSomething: function() {
      alert(1);
    }
  }
});
</script>

The Vue application is a bit more verbose, but note how the markup has a direct connection between the action ("click") and the function that will be called. Vue's code doesn't have a tie back to the DOM (outside of the el portion where we define where it needs to work). This was easily one of the things that sold me on Vue the most — it feels easier to tell what is going on. Also, I didn't need to worry so much about the ID value and selectors. If I change the class or ID of the button, I don't need to go back into my code and worry about updating selectors.

Let's consider another example: finding and changing text in the DOM. Imagine that button, on click, now changes the text of another part of the DOM.

HTML

<button id="myButton">Click Me!</button>
<span id="result"></span>

<!-- More stuff... -->

<script>
$(document).ready(function() {

  $('#myButton').click(function() {
    $('#result').text('You clicked me, thanks!');
  });

});
</script>

I've added a new span and now, when the button is clicked, we use another selector to find it and use a jQuery utility method to change the text inside it. Now consider the Vue version:

HTML

<div id="app">
  <button v-on:click="doSomething">Click Me!</button>
  <!-- On click, change text in this span -->
  <span>{{resultText}}</span>
</div>

<script>
const app = new Vue({
  el: '#app',
  data: {
    resultText: ''
  },
  methods: {
    doSomething: function() {
      this.resultText = 'You clicked me, thanks!';
    }
  }
});
</script>

In this example, we're using Vue's template language (the highlighted line) to specify that we want to render a variable inside the span, which is resultText in this case. Now, when the button is clicked, we change that value and the span's inner text will change automatically.

Reading and writing form variables

Working with forms is probably one of the most common — and useful — things that we can do with JavaScript. Even before JavaScript, most of my early "web development" was writing Perl script to handle form submissions. As the primary way of accepting user input, forms have always been critical to the web and that's probably going to stay the same for quite some time. Let's consider a simple jQuery example of reading a few form fields and setting another:

HTML

<form>
  <input type="number" id="first"> + 
  <input type="number" id="second"> =
  <input type="number" id="sum"> 
  <button id="sumButton">Sum</button>
</form>

<script>
$(document).ready(function() {
  let $first = $('#first');
  let $second = $('#second');
  let $sum = $('#sum');
  let $button = $('#sumButton');
  
  $button.on('click', function(e) {
    e.preventDefault();
    let total = parseInt($first.val(),10) + parseInt($second.val(),10);
    $sum.val(total);
  });
});
</script>

This code demonstrates how jQuery can both read and write via the val() method. We end up getting four items from the DOM (all three form fields and the button) and use simple math to generate a result. Now consider the Vue version:

HTML

<form id="myForm">
  <input type="number" v-model.number="first"> + 
  <input type="number" v-model.number="second"> =
  <input type="number" v-model="sum"> 
  <button @click.prevent="doSum">Sum</button>
</form>

<script>
new Vue({
  el: '#myForm',
  data: {
    first: 0,
    second: 0,
    sum: 0
  },
  methods: {
    doSum: function() {
      this.sum = this.first + this.second;
    }
  }
})
</script>

This introduces some interesting Vue shortcuts. First, <a href="https://vuejs.org/v2/api/#v-model" target="_blank">v-model</a> is how Vue creates two way data binding between values in the DOM and in JavaScript. The data block variables will automatically sync up with the form fields. Change the data, and the form updates. Change the form, and the data updates. The .number is a flag to Vue to treat the inherit string values of form fields as numbers. If we leave this off and do addition as we are, we'll see string additions and not arithmetic. I've been working with JavaScript for nearly a century and still screw this up.

Another neat "trick" is @click.prevent. First, @click defines a click handler for the button, then the .prevent portion blocks the browser’s default behavior of submitting the form (the equivalent of event.preventDefault()).

The final bit is the addition of the doSum method that's bound to that button. Note that it simply works with the data variables (which Vue makes available in the this scope).

While this is mostly my personal feeling here, I really love the lack of query selectors in the script when writing in Vue and how the HTML is much more clear about what it's doing.

Finally, we could even get rid of the button completely:

HTML

<form id="myForm">
  <input type="number" v-model.number="first"> + 
  <input type="number" v-model.number="second"> =
  <input type="number" v-model="sum"> 
</form>

<script>
new Vue({
  el: '#myForm',
  data: {
    first: 0,
    second: 0
  },
  computed: {
    sum: function() {
      return this.first + this.second;
    }
  }
})
</script>

One of the cooler features of Vue is computed properties. They are virtual values that recognize when their derived values are updated. In the code above, as soon as any of the two form fields change, the sum will update. This works outside of form fields too. We could render the sum like so:

HTML

The total is {{sum}}.

Working with Ajax

It’s commendable how easy jQuery has made it to use Ajax. In fact, I can say I've done Ajax "the vanilla" way probably a grand total of one time. (If you're curious, you can take a look at the spec for XMLHttpRequest and probably be happy you avoided it yourself.) jQuery's simple $.get(...)method worked in a large number of cases and when it’s needed for something more complex, $.ajax() made it easy as well. Another thing jQuery did well is the way it handles JSONP requests. While mostly unnecessary now with CORS, JSONP was a way to handle making requests to APIs on different domains.

So, what does Vue do for you to make Ajax easier? Nothing!

OK, that sounds scary but it really isn't. There are many options out there for working with HTTP requests, and Vue.js took a more agnostic route of letting us, the developers, decide how we want to handle it. So yes, that does mean a bit more work, but we've got some great options.

The first one to consider is Axios, this is a Promise-based library that is very popular among the Vue community. Here's a simple example of it in action (taken from their README file):

Javascript

axios.get('/user?ID=12345')
  .then(function (response) {
    // handle success
    console.log(response);
  })
  .catch(function (error) {
    // handle error
    console.log(error);
  })
  .then(function () {
    // always executed
  });

Axios supports POST requests, of course, and lets us specify headers among many other options.

While Axios is very popular among Vue developers, it isn't something that really clicked with me. (At least not yet.) Instead, I've been much more a fan of Fetch. Fetch is not an external library but is a web standard way of performing HTTP requests. Fetch has very good support at roughly 90% of browsers, though that means it isn't completely safe to use, but we can always use a polyfill we need to.

Like Axios, Fetch is Promise-based and has a friendly API:

Javascript

fetch('http://example.com/movies.json')
  .then(function(response) {
    return response.json();
  })
  .then(function(myJson) {
    console.log(JSON.stringify(myJson));
  });

Both Axios and Fetch cover all types of HTTP requests, so either will fit an any number of needs. Let's look at a simple comparison. Here's a simple jQuery demo that makes use of the Star Wars API.

HTML

<h1>Star Wars Films</h1>
<ul id="films">
</ul>

<script>
$(document).ready(function() {
  $.get('https://swapi.com/api/films', function(res) {
    let list = '';
    res.results.forEach(function(r) {
      list += `<li>${r.title}</li>`;
    });
    $('#films').html(list);
  });
});
</script>

In the sample above, I use $.get to hit the API and return a list of films. Then I generate a list of titles as li tag elements with that data and insert it all into a ul block.

Now, let's consider an example of this using Vue:

HTML

<div id="app">
  <h1>Star Wars Films</h1>
  <ul>
    <li v-for="film in films">{{film.title}}</li>
  </ul>  
</div>

<script>
const app = new Vue({
  el: '#app',
  data: {
    films: []
  }, 
  created() { 
    fetch('https://swapi.com/api/films')
    .then(res => res.json())
    .then(res => {
      this.films = res.results;  
    });
  }
})
</script>

Probably the best part of this is the use of the v-for template. Notice how Vue isn't concerned with the layout (well, at least the JavaScript). The data is fetched from the API. It’s assigned a variable. The layout handles displaying it. I've always hated having HTML in my JavaScript and, while solutions exist for that with jQuery, having it baked into Vue makes it a natural fit.

A full (if somewhat trivial) example

To bring it home a bit, let's consider a more real world example. Our client has asked us to build a fancy Ajax-enabled front-end search interface to a product API. The feature list includes:

  • Support filtering by name and product category
  • Form validation such that we must supply a search term or a category
  • While the API is being hit, show a message to the user and disable the submit button
  • When done, handle reporting that no products were shown or list the matches

Let's begin with the jQuery version. First, the HTML:

HTML

<form>
  <p>
    <label for="search">Search</label>
    <input type="search" id="search">
  </p>
  <p>
    <label for="category">Category</label>
    <select id="category">
      <option></option>
      <option>Food</option>
      <option>Games</option>
    </select>
  </p> 
  <button id="searchBtn">Search</button>
</form>

<div id="status"></div>
<div id="results"></div>

There's a form with our two filters and two divs. One's used as a temporary status when searching or reporting errors and one is used to render results. Now, check out the code.

Javascript

const productAPI = 'https://wt-c2bde7d7dfc8623f121b0eb5a7102930-0.sandbox.auth0-extend.com/productSearch';

$(document).ready(() => {
  let $search = $('#search');
  let $category = $('#category');
  let $searchBtn = $('#searchBtn');
  let $status = $('#status');
  let $results = $('#results');
  
  $searchBtn.on('click', e => {
    e.preventDefault();
    
    // First clear previous stuff
    $status.html('');
    $results.html('');

    // OK, now validate form
    let term = $search.val();
    let category = $category.val();
    if(term === '' && category === '') {
      $status.html('You must enter a term or select a category.');
      return false;
    }

    $searchBtn.attr('disabled','disabled');
    $status.html('Searching - please stand by...');
    
    $.post(productAPI, { name:term, category:category }, body => {
      $searchBtn.removeAttr('disabled');
      $status.html('');

      if(body.results.length === 0) {
        $results.html('<p>Sorry, no results!</p>');
        return;
      }
      
      let result = '<ul>';
      body.results.forEach(r => {
        result += `<li>${r.name}</li>`
      });
      result += '</ul>';
      $results.html(result);
    });
    
  });
});

The code begins by creating a set of variables for each of the DOM items we want to work with — the form fields, button, and divs. The core of the logic is within the click handler for the button. We do validation, and if everything is OK, do a POST request against the API. When it returns, we either render the results or show a message if nothing was matched.

You can work with a complete version of this demo using the CodePen below.

Now let's consider the Vue version. Again, let's start with the layout:

HTML

<div id="app">
  <form>
    <p>
      <label for="search">Search</label>
      <input type="search" v-model="search">
    </p>
    <p>
      <label for="category">Category</label>
      <select v-model="category">
        <option></option>
        <option>Food</option>
        <option>Games</option>
      </select>
    </p>
    <button @click.prevent="searchProducts" :disabled="searchBtnDisabled">Search</button>
  </form>

    <div v-html="status"></div>
    <ul v-if="results">
      <li v-for="result in results">{{result.name}}</li>
    </ul>
</div>

From the top, the changes include:

  • Wrapping the layout in a div that can be used to let Vue know where to work.
  • Using v-model for the form fields to make it easy to work with the data.
  • Using @click.prevent to handle doing the main search operation.
  • Using :disabled to bind whether or not the button is disabled to a value in the Vue application (we'll see that in action in a moment).
  • The status value is a bit different than earlier examples. While jQuery has a specific method to set text in a DOM item and another for HTML, Vue requires using v-html when assigning HTML to a value that's going to be rendered. If we tried to do {{status}} with HTML, the tags would be escaped.
  • Finally, using v-if to conditionally render a list of results along with v-for to handle the iteration.

Now let's look at the code.

Javascript

const productAPI = 'https://wt-c2bde7d7dfc8623f121b0eb5a7102930-0.sandbox.auth0-extend.com/productSearch';

const app = new Vue({
  el: '#app',
  data: {
    search: '',
    category: '',
    status: '',
    results: null,
    searchBtnDisabled: false
  },
  methods: {
    searchProducts:function() {
      this.results = null;
      this.status = '';
      
      if(this.search === '' && this.category === '') {
        this.status = 'You must enter a term or select a category.';
        return;
      }

      this.searchBtnDisabled = true;
      this.status = 'Searching - please stand by...';
      
      fetch(productAPI, {
        method: 'POST',
        headers: {
          'Content-Type':'application/json'
        },
        body: JSON.stringify({name:this.search,category:this.category})
      }).then(res => res.json())
      .then(res => {
        this.status = '';
        this.searchBtnDisabled = false;
        this.results = res.results;
        if(this.results.length === 0) this.status = '<p>Sorry, no results!</p>';
      });
      
    }
  }
});

The first block worth calling out is the set of data fields. Some map to form fields and others to results, status messages, and the like. The searchProducts method handles much of the same stuff as the jQuery version but, in general, there's much less code directly tied to the DOM. For example, even though we know the results are listed in an unordered list, the code itself doesn't worry about that. It simply assigns the value and the markup handles rendering it. Overall, the JavaScript code is much more concerned about logic in comparison to the jQuery code which "feels" like a much nicer separation of concerns.

As before, I've got a CodePen for you to try this out yourself:

Death to jQuery! Long Live Vue!

OK, that's a bit over the top. As I said in the beginning, I absolutely think that you shouldn't change a thing if like working with jQuery and it's working for you.

I can say, however, that Vue feels like a great "next step" for people who are used to working with jQuery. Vue supports complex applications and has a great command line tool for scaffolding and building projects. But for simpler tasks, Vue works as a great "modern jQuery" replacement that has become my tool of choice for development!

Thanks for reading. If you liked this post, share it with all of your programming buddies!