patternjavascriptMinor
Simple JavaScript Backbone.Js tool to highlight multiple search terms
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:
-
-
-
-
-
-
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
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 listImplementation:
```
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
This happens because
One way you could solve this is to check for your
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.