HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

Simple JavaScript Backbone.Js tool to highlight multiple search terms

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
simplesearchjavascriptbackbonemultipletermshighlighttool

Problem

I wrote a simple JavaScript tool to highlight multiple keywords at the same time in some text. It uses different color for each keyword, and also shows the count of matches.

I'm using Backbone.js with the following class structure:

-
App.Model: the main model, keeping track of:

  • the keywords



  • the words in the text and their count



  • the original text



  • the transformed text with highlighted words



-
App.OriginalTab, App.HighlightedTab: View classes, for showing the original text and the highlighted text, respectively, in tabs

-
App.KeywordView: a View class, handling the input of new keywords

-
App.Keyword: a Model class, keeping track of a keyword and its count in the text

-
App.KeywordList: a Collection class, keeping track of the keywords. Changes to the collection trigger updating the highlighted text

-
App.KeywordsView: a View class, to render the list of keywords, highlighted using the same color as the highlight in the text, showing the count, and a button to remove from the list

Implementation:

```
var App = window.App = {};

_.templateSettings = { interpolate: /\{\{(.+?)\}\}/g };

App.Model = Backbone.Model.extend({
defaults: {
original: '',
keywords: [],
words: {},
highlighted: ''
},
initialize: function () {
this.on('change:original', this.onOriginalUpdated, this);
this.on('change:keywords', this.onKeywordsUpdated, this);
},
updateWords: function () {
var words = {};
_.each(this.get('original').split(/\W+/), function (word) {
word = word.toLowerCase();
words[word] = (words[word] || 0) + 1;
});
this.set({words: words});
},
updateHighlighted: function () {
var highlighted = this.escape('original');
var cnt = 1;
_.each(this.get('keywords'), function (keyword) {
var pattern = '\\b' + keyword;
var cname = 'hlt' + cnt++;
highlighted = highli

Solution

One quick note (I'm so sorry I have no chance to read the full code)
please be careful when using reference values (i.e object and arrays) in defaults, let me show you one example of how this could be turned into an unexpected behavior:

A = Backbone.Model.extend({defaults:{arr: ['a', 'b']}})
a = new A()
a.get('arr').push('c')
a.get('arr')
>> ["a", "b", "c"]
b = new A()
b.get('arr')
>>["a", "b", "c"]


This happens because arr attributes in both a and b instances of Model A refers to same value which is arr array reference in memory so when you are doing a.get('arr').push('c') you actually manipulate the arr value you referenced when you first declared defaults so any next instance of Model A will use the new value of arr which is ["a", "b", "c"] I hope this is clear.

One way you could solve this is to check for your defaults in initialize method instead so it'll create new instance of arr whenever there's no one present if we apply this to your initialize method:

initialize: function() {
    if (!this.get('keywords')) {
        this.set({
            keywords: new Array()
        });
    }

    if (!this.get('words')) {
        this.set({
            words: new Object()
        });
    }
    this.on('change:original', this.onOriginalUpdated, this);
    this.on('change:keywords', this.onKeywordsUpdated, this);
}

Code Snippets

A = Backbone.Model.extend({defaults:{arr: ['a', 'b']}})
a = new A()
a.get('arr').push('c')
a.get('arr')
>> ["a", "b", "c"]
b = new A()
b.get('arr')
>>["a", "b", "c"]
initialize: function() {
    if (!this.get('keywords')) {
        this.set({
            keywords: new Array()
        });
    }

    if (!this.get('words')) {
        this.set({
            words: new Object()
        });
    }
    this.on('change:original', this.onOriginalUpdated, this);
    this.on('change:keywords', this.onKeywordsUpdated, this);
}

Context

StackExchange Code Review Q#61125, answer score: 4

Revisions (0)

No revisions yet.