Showing posts with label jQuery. Show all posts
Showing posts with label jQuery. Show all posts

Monday, January 28, 2019

A simple chat room in Vue.Js

Let's see how to build a simple chat-room using Vue.Js and why Vue.js is awesome.

Vue.Js is awesome. I've used other JavaScript libs throughout the years and as a long time Scrum master and developer, I use to do a technical retrospective after each project. In my experience, when compared to Vue.Js, other libs are heavy, slow or  over-complicated. Just do a quick search to learn why people love it.

On this post, I want to demo how elegant and simple Vue is so I built a very simple chat room frontend using Vue.js, Bootstrap and a few CDNs. You can find the source code here. It's one simple html page. Just download and open in your browser.

The source code

You can find the code for a simple chat room below. A little more then 30 lines of code to build this frontend. Wow, that's efficiency.

// Vue-ChatRoom.js: A simple chatroom to demo how simple and elegant Vue.Js is
// By: Bruno Hildenbrand
// Source: https://github.com/hd9/vue-chatroom
// blog post available at: blog.hildenco.com
const app = new Vue({
el: '#chat',
data: {
name: 'Bruno',
msg: '',
color: getRandomColor(),
messages: [
{ name: '[System Bot]', msg: initialMsg, tm: (new Date()).toLocaleTimeString() },
],
participants: [
// { name: 'Bruno', class: 'label label-success' },
]
},
methods: {
send(){
if (this.msg.length > 0){
this.messages.push({name: this.name, msg: this.msg, tm: (new Date()).toLocaleTimeString(), color: this.color})
this.msg = '';
this.scrollBottom();
}
},
quit() {
if (confirm('Are you sure you want to quit?')){
window.close();
}
},
scrollBottom(){
Vue.nextTick(function () {
var div = document.getElementById("chat-content");
div.scrollTop = div.scrollHeight;
});
}
}
});
view raw Vue-ChatRoom.js hosted with ❤ by GitHub

Posting Messages to the Room

Of course, we would like to send messages to the chat room. It's as simple as running the code below on your Developer Tools (F12) console:
app.messages.push({name: 'Some Name', msg: 'Test123', tm: (new Date()).toLocaleTimeString(), color: 'red'});
See that new messages are auto-added to the room on the bottom with very little effort. Simple, clean, elegant.

Future Enhancements

Out of the box, the code above simulates a chat room frontend for just one user. Yes you can still hack it trough the console to add other users (by pushing to the participants array) but it's not usable yet. One interesting exercise would be enhancing the above code with WebSockets so that multiple users can connect at the same room and chat trough it.

I already have that code written in SignalR Core and a ASP.NET Core web app as the backend and will soon open source it. Stay tuned.

Source Code

Vue did all the work. All the rest is available on my GitHub.

See Also

Monday, July 2, 2018

Building a dynamic table with Vue.Js and Bootstrap 4

Vue.js makes it easy to manipulate the DOM and build dynamic elements. Read to understand.

You probably had that requirement to build tables where the user can Edit/Remove/Add items to it dynamically. With jQuery that required handling a lot of events usually leading to bugs and wasted time. Turns out that with Vue.Js, if modeled correctly, that's extremely easy. Let's take a look.

Adding Bootstrap 4

First, to make it look cool and save us some time prepping html, css and layout stuff, let's use Bootstrap's starter template to save us some dev time building the base html page.

Save that file and add Vue's dev version from the cdn on the bottom of the file with:

    <!-- Vue development version, includes helpful console warnings -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

With Bootstrap and Vue loaded, let's do some code.

Building the Vue Instance

My agenda class below will be responsible for rendering the dynamic table. Its syntax looks like this:
        const agenda = new Vue({
            el: '#agenda',
            data: {
                topics: [
                    new Topic({ title: 'Item 1' }),
                    new Topic({ title: 'Item 2' }),
                    new Topic({ title: 'Item 3' }),
                ]
            },
            computed: {

            },
            methods: {
                add() {
                    this.topics.push(new Topic({ editing: true }))
                },
                save() {
                    alert("todo :: submit to server");
                },
                cancelEdits() {
                    this.topics.forEach(el => el.editing = false );
                }
            }
        });

That represents our Vue instance, the start point of our Vue app. See how simple it is? That's the beauty of Vue. Now let's revise our Topic class. Our agenda app consists of a table of a list of topics in which each row is an instance of the Topic class described below:

        const Topic = function(model){
            var self = this;
            var m = model || {};
            
            self.oTitle = m.title || "";
            self.title = m.title;
            self.required = m.required || false;
            self.orequired = self.required;
            self.editing = m.editing;

            self.update = function(i){
                if ((self.title || "").length < 3){
                    alert('At least 3 chars are required to save');
                    return;
                }

                agenda.topics[i].title = self.title;
                self.editing = false;
            }

            self.edit = function(){
                agenda.cancelEdits();
                self.editing = true;
            }

            self.cancel = function(i){
                if (!self.oTitle){
                    agenda.topics.splice(i,1);
                    return;
                }

                self.title = self.oTitle;
                self.required = self.orequired;
                self.editing = false;
            }

            self.remove = function(i){
                if (confirm('Are you sure you want to remove this topic?')){
                    agenda.topics.splice(i,1);
                }
            }
            
            return self;
        }

Reviewing the HTML

The part of the HTML that deserves some comment is how we dynamically list the records using Vue's v-for directive binding. The code below shows how this is accomplished elegantly using Vue:
    <tr v-for="(t, i) in topics">

So, for each element in agenda.topics, Vue will render a tr for us with this piece of code:

<tr v-for="(t, i) in topics">
                    <th scope="row">{{ i + 1 }}</th>
                    <td>
                        <span v-if="t.editing">
                            <input v-model="t.title" @@keyup.enter="t.update(i)"/>
                        </span>
                        <span v-else>
                            {{ t.title }}
                        </span>
                    </td>
                    <td class="text-center">
                        <span v-if="t.editing">
                            <input type="radio" value="true" v-model="t.required"> Yes
                            <input type="radio" value="false" v-model="t.required"> No
                        </span>
                        <span v-else>
                            {{ t.required == "true" ? 'Yes' : 'No' }}
                        </span>
                    </td>
                    <td class="text-center">
                        <span v-if="t.editing">
                            <button class="btn btn-outline-info btn-sm" v-on:click="t.update(i)">Update</button>
                            <button class="btn btn-outline-danger btn-sm" v-on:click="t.cancel(i)">Cancel</button>
                        </span>
                        <span v-else>
                            <button class="btn btn-outline-info btn-sm" v-on:click="t.edit(i)">Edit</button>
                            <button class="btn btn-outline-danger btn-sm" v-on:click="t.remove(i)">Remove</button>
                        </span>
                    </td>
                </tr>

The source code for this page is available on my GitHub repo

Conclusion

The objective of this post is to demo how simple things become when using the right tools. Vue in my experience has matured and deserves a lot of praise in how it handles reactivity, simplifies, organizes and accelerates development.

See Also

Monday, April 30, 2018

Copying data to memory with JavaScript and jQuery

How to copying data to memory with JavaScript and jQuery? Read and understand.

A nice feature to have in your site is the ability of letting users copy certain pieces of data to the memory. This is useful for example to copying things such as Ids, phone numbers, urls or connection strings. Stuff that's complicated to type or very error prone.

Turns out that a simple solution can be achieved using JavaScript and jQuery. Let's see how.

A Simpler Approach

Here's how I approached it:

1. add a class to show a copy icon whenever you hover a DOM element:

Ex. class="icon-clipboard"

2. add a css class to identify what you want to copy:

Ex. class="copyableTemplate"

3. add the data to copy using the "data-clipboard" attribute:

Ex. data-clipboard="http://lipsum.com/"

4. handle the click event on the copy icon and get the data associated to it:

Ex. $('body').on('click', 'div.icon-clipboard', function() { })

5. copy to memory using the browser's api:

Ex. document.execCommand('copy');

Source Code:

<html>
<head>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
<style>
div.copyableTemplate div{
display:none;
}
div.copyableTemplate:hover div{
display:inline;
}
.icon-clipboard:before {
content: " Copy URL... ";
cursor: pointer;
font-size: 0.9em;
background-color: crimson;
color: white;
padding: 3px;
border-radius: 10px;
}
</style>
<script>
$(document).ready(function(){
// Init Clipboard
var initClipboard = function() {
$('body').on('click', 'div.icon-clipboard', function() {
console.log('onClick');
var data = $(this).data('clipboard');
$('#clipboard').show();
$('#clipboard').val(data);
if (data) {
$('#clipboard')[0].select();
}
// try copying to memory
try {
document.execCommand('copy');
alert('Value: "' + data + '" copied to memory!');
} catch (err) {
console.log('Error copying data to clipboard. Please check if your browser supports this feature..');
}
// need to show/hide else, textarea loses value
$('#clipboard').hide();
});
}
initClipboard();
});
</script>
</head>
<body>
<h1>Copy data using Javascript and jQuery</h1>
<textarea id="clipboard" style="display:none;"></textarea>
<div class="copyableTemplate">
Quisque eleifend sapien sed interdum fermentum. Sed suscipit nibh massa, in maximus nulla imperdiet vitae.
<div class="icon-clipboard" data-clipboard="http://lipsum.com/" title="Click to copy the Id to the clipboard"></div>
</div>
<p style="padding-top:20px">
Hope it helps!<br>
Bruno Hildenbrand
</p>
</body>
</html>

See Also

Wednesday, February 14, 2018

Export HTML to PDF using JavaScript

Building PDF files with JavaScript is simpler than you think. If you use the right tools.
Sometimes you get those requests to "export to pdf" a given web page you developed. Turns out that sometimes, and just sometimes =), it's too complex to produce a custom report, the time to setup a reporting server, the costs, etc, are too impeditive. What can we do?

It can be easily done using two popular javascript libraries: jQuery and the excellent JsPdf. Since the PDF is rendered by JavaScript, testing is as simple as running the following on your browser.
<html>
<head>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
<style>
div.copyableTemplate div{
display:none;
}
div.copyableTemplate:hover div{
display:inline;
}
.icon-clipboard:before {
content: " Copy URL... ";
cursor: pointer;
font-size: 0.9em;
background-color: crimson;
color: white;
padding: 3px;
border-radius: 10px;
}
</style>
<script>
$(document).ready(function(){
// Init Clipboard
var initClipboard = function() {
$('body').on('click', 'div.icon-clipboard', function() {
console.log('onClick');
var data = $(this).data('clipboard');
$('#clipboard').show();
$('#clipboard').val(data);
if (data) {
$('#clipboard')[0].select();
}
// try copying to memory
try {
document.execCommand('copy');
alert('Value: "' + data + '" copied to memory!');
} catch (err) {
console.log('Error copying data to clipboard. Please check if your browser supports this feature..');
}
// need to show/hide else, textarea loses value
$('#clipboard').hide();
});
}
initClipboard();
});
</script>
</head>
<body>
<h1>Copy data using Javascript and jQuery</h1>
<textarea id="clipboard" style="display:none;"></textarea>
<div class="copyableTemplate">
Quisque eleifend sapien sed interdum fermentum. Sed suscipit nibh massa, in maximus nulla imperdiet vitae.
<div class="icon-clipboard" data-clipboard="http://lipsum.com/" title="Click to copy the Id to the clipboard"></div>
</div>
<p style="padding-top:20px">
Hope it helps!<br>
Bruno Hildenbrand
</p>
</body>
</html>

Conclusion

Exporting HTML to PDF is a simple task if we use the write tools. Hope it helps.

References

See Also

About the Author

Bruno Hildenbrand