ui-select multiselect is very slow in displaying the choices - angularjs

I ran into this problem, and I don't know how to solve it. I have used a ui-select multiselect in my page. First, a http.get request is made to a url which gets the data, then the ui-select choices are populated. The data is big - the length of the data is 2100. This data is to be shown as choices. (The data is fetched at the beginning during the loading of the page and is stored in an array)
But the problem is each time I click on the multiselect to select a choice, it takes 4-5 seconds to populate the list and the page becomes very slow. What do I do to reduce this time?
The choices data is stored in an array, the datatype is array of strings.
<ui-select multiple ng-model="selectedFields.name" style="width: 100%;">
<ui-select-match placeholder="Select fields...">{{$item}}</ui-select-match>
<ui-select-choices repeat="fields in availableFields | filter:$select.search">
{{fields}}
</ui-select-choices>
</ui-select>
in the controller,
$scope.selectedFields = {};
$scope.selectedFields.name = [];
$scope.init = function() {
$http.get(url)
.success( function(response, status, headers, config) {
availableFields = response;
})
.error( function(err) {
});
};
$scope.init();
If not this way, is there any other options/choice I can work with which doesn't delay showing the select-choices?

This is a known issue in ui-select. I tried the following ways, both work
1) There is a workaround for this - use
| limitTo: 100
This limits the choice display to 100 but all the choices can be selected. Look at this thread for more details.
2) Since some of the time, there is a need to display the entire list in the choices, 1) is not a viable option. I used a different library - selectize.js. Here's a plunker demo given in the page

Here is complete solution that decorates uiSelectChoices directive.
Items are populated progressively as the user scrolls.
Also takes care of searches in the scrolls.
Also works for all values of position={auto, up, down}
Example
<ui-select-choices
position="up"
all-choices="ctrl.allTenThousandItems"
refresh-delay="0"
repeat="person in $select.pageOptions.people | propsFilter: {name: $select.search, age: $select.search} ">
<div ng-bind-html="person.name | highlight: $select.search"></div>
<small>
email: {{person.email}}
age: <span ng-bind-html="''+person.age | highlight: $select.search"></span>
</small>
</ui-select-choices>
Working Plnkr
Also with With v0.19.5
The directive
app.directive('uiSelectChoices', ['$timeout', '$parse', '$compile', '$document', '$filter', function($timeout, $parse, $compile, $document, $filter) {
return function(scope, elm, attr) {
var raw = elm[0];
var scrollCompleted = true;
if (!attr.allChoices) {
throw new Error('ief:ui-select: Attribute all-choices is required in ui-select-choices so that we can handle pagination.');
}
scope.pagingOptions = {
allOptions: scope.$eval(attr.allChoices)
};
attr.refresh = 'addMoreItems()';
var refreshCallBack = $parse(attr.refresh);
elm.bind('scroll', function(event) {
var remainingHeight = raw.offsetHeight - raw.scrollHeight;
var scrollTop = raw.scrollTop;
var percent = Math.abs((scrollTop / remainingHeight) * 100);
if (percent >= 80) {
if (scrollCompleted) {
scrollCompleted = false;
event.preventDefault();
event.stopPropagation();
var callback = function() {
scope.addingMore = true;
refreshCallBack(scope, {
$event: event
});
scrollCompleted = true;
};
$timeout(callback, 100);
}
}
});
var closeDestroyer = scope.$on('uis:close', function() {
var pagingOptions = scope.$select.pagingOptions || {};
pagingOptions.filteredItems = undefined;
pagingOptions.page = 0;
});
scope.addMoreItems = function(doneCalBack) {
console.log('new addMoreItems');
var $select = scope.$select;
var allItems = scope.pagingOptions.allOptions;
var moreItems = [];
var itemsThreshold = 100;
var search = $select.search;
var pagingOptions = $select.pagingOptions = $select.pagingOptions || {
page: 0,
pageSize: 20,
items: $select.items
};
if (pagingOptions.page === 0) {
pagingOptions.items.length = 0;
}
if (!pagingOptions.originalAllItems) {
pagingOptions.originalAllItems = scope.pagingOptions.allOptions;
}
console.log('search term=' + search);
console.log('prev search term=' + pagingOptions.prevSearch);
var searchDidNotChange = search && pagingOptions.prevSearch && search == pagingOptions.prevSearch;
console.log('isSearchChanged=' + searchDidNotChange);
if (pagingOptions.filteredItems && searchDidNotChange) {
allItems = pagingOptions.filteredItems;
}
pagingOptions.prevSearch = search;
if (search && search.length > 0 && pagingOptions.items.length < allItems.length && !searchDidNotChange) {
//search
if (!pagingOptions.filteredItems) {
//console.log('previous ' + pagingOptions.filteredItems);
}
pagingOptions.filteredItems = undefined;
moreItems = $filter('filter')(pagingOptions.originalAllItems, search);
//if filtered items are too many scrolling should occur for filtered items
if (moreItems.length > itemsThreshold) {
if (!pagingOptions.filteredItems) {
pagingOptions.page = 0;
pagingOptions.items.length = 0;
} else {
}
pagingOptions.page = 0;
pagingOptions.items.length = 0;
allItems = pagingOptions.filteredItems = moreItems;
} else {
allItems = moreItems;
pagingOptions.items.length = 0;
pagingOptions.filteredItems = undefined;
}
} else {
console.log('plain paging');
}
pagingOptions.page++;
if (pagingOptions.page * pagingOptions.pageSize < allItems.length) {
moreItems = allItems.slice(pagingOptions.items.length, pagingOptions.page * pagingOptions.pageSize);
}
for (var k = 0; k < moreItems.length; k++) {
pagingOptions.items.push(moreItems[k]);
}
scope.calculateDropdownPos();
scope.$broadcast('uis:refresh');
if (doneCalBack) doneCalBack();
};
scope.$on('$destroy', function() {
elm.off('scroll');
closeDestroyer();
});
};
}]);

As stated, ui-select is having quite a few performance issues, but there is a workaround for the limit issue.
If you follow akashrajkn's approach then you will notice that it will actually cut out important pieces of data because it will only render 100 at a time. There is a fix that has passed the unit tests and it can be found on the thread here:
https://github.com/angular-ui/ui-select/pull/716
Basically, if you are storing the javascript file locally, then you can adjust the unminified version. All you need to do is implement the changes he made in the pull request and it should help out significantly. In order to apply the limiting factor, take a look at the below, modified example:
<ui-select multiple ng-model="selectedFields.name" limit = "10" style="width: 100%;">
<ui-select-match placeholder="Select fields...">{{$item}}</ui-select-match>
<ui-select-choices repeat="fields in availableFields | filter:$select.search | limitTo:$select.limit ">
{{fields}}
</ui-select-choices>
</ui-select>
The above will limit your data in the drop down while also maintaining the level of consistency needed.

Because I cannot leave a comment (not enough rep) I write this as an answer and I am sorry it is no answer for the problem.
#bhantol I changed the following line of code to your solution which is working perfectly for me so far
for (var k = 0; k < moreItems.length; k++) {
pagingOptions.items.push(moreItems[k]);
}
for (var k = 0; k < moreItems.length; k++) {
if (pagingOptions.items.indexOf(moreItems[k]) == -1){
pagingOptions.items.push(moreItems[k]);
}
}
This prevents duplicated items from showing up if the user is starting to write a filter and then deletes it.
Also I just figured out that if the list is smaller than 20 items it will not work so I changed:
if (pagingOptions.page * pagingOptions.pageSize < allItems.length) {
moreItems = allItems.slice(pagingOptions.items.length, pagingOptions.page * pagingOptions.pageSize);
}
to:
if (pagingOptions.page * pagingOptions.pageSize < allItems.length) {
moreItems = allItems.slice(pagingOptions.items.length, pagingOptions.page * pagingOptions.pageSize);
}
else{ moreItems = allItems;}
Maybe this will help you somehow and sorry again for not answering the question.

Related

Angular - multiple keywords in search bar - how to exclude search results which doesnt match each keyword?

I have a search field where I want to display products based on the keyword(s). So far products are being shown which match EITHER one of the keywords but I want the search results displayed ONLY when ALL keywords are matched. I tried to do a for loop through the arguments (the input /keywords)and used angulars filter but its not really working. Any ideas?
var app=angular.module('app', []);
app.controller('appController', function($scope, $http) {
$scope.search = function(key) {
function listOfItems(key) {
var array = Array.prototype.slice.call(arguments);
var keywords = "";
for (var i = 0; i < array.length; i++) {
keywords += array[i] + '+'
}
return keywords.slice(0, keywords.length - 1);
}
$scope.parameter = listOfItems(key);
$http.('http://example.com/store/?keyword=' + $scope.parameter + '&token=11111111.22222')
.then(function(prods) {
return prods.data;
if($scope.parameter){
$scope.prods = prods.data;
}
})
}
})
html:
<input ng-model="key" type="text" class="form-control>
<button type=" submit " ng-click="search(key) ">
</button>
<div ng-repeat="shop in shops | filter: search(key) ">
<p>{{shop.title}}</p>
<p>{{shop.description}}</p>
</div>

Angular - Trouble with ng-change

I am still a little new to Angular, and I am having trouble setting the default select option, if that option is the only one in the array. What happens specifically is that the select does default, however, the shipping cost is not being calculated. It only calculates if the user chooses it from the drop down. I think the issue may be because with the ng-change on the select element, but I am not sure.
In my HTML:
<select class="form-control" ng-change="updateShipper()" name="shipMethod"
ng-model="currentOrder.LineItems[0].ShipperName"
ng-show="user.ShipMethod.ShipperSelectionType == 'UserDropDown'"
ng-options="shipper.Name as (shipper.Name + ' ' + (shipper.ShippingRate.Price | currency | xlat)) for shipper in shippers"
ng-required="!currentOrder.IsMultipleShip() && user.ShipMethod != null" >
<option value=""></option>
In my controller:
scope.$watch('shippers', function(val) {
if(angular.isDefined(val)){
$timeout(function() {
if(val.length === 1){
scope.currentOrder.LineItems[0].ShipperName = val[0].Name;
}
}, 0);
}
});
$scope.updateShipper = function(li) {
$scope.shippingUpdatingIndicator = true;
$scope.shippingFetchIndicator = true;
if (!li) { // at the order level
angular.forEach($scope.shippers, function(s) {
if (s.Name == $scope.currentOrder.LineItems[0].ShipperName)
$scope.currentOrder.Shipper = s;
});
angular.forEach($scope.currentOrder.LineItems, function(item) {
item.ShipperName = $scope.currentOrder.Shipper ? $scope.currentOrder.Shipper.Name : null;
item.ShipperID = $scope.currentOrder.Shipper ? $scope.currentOrder.Shipper.ID : null;
});
saveChanges(function() {
$scope.shippingUpdatingIndicator = false;
$scope.shippingFetchIndicator = false;
});
}
else { // at the lineitem level for multiple shipping
angular.forEach($scope.shippers, function(s) {
if (s.Name == li.ShipperName)
li.Shipper = s;
});
li.ShipperName = li.Shipper.Name;
li.ShipperID = li.Shipper.ID;
saveChanges(function() {
$scope.shippingUpdatingIndicator = false;
$scope.shippingFetchIndicator = false;
});
}
};
Try ng-init="updateShipper()". Then set the initial value of your model in the controller like $scope.currentOrder.LineItems[0].ShipperName = 0(or whatever).

Angular ui-select with or conditioned filter

I am trying to use or condition filter in ui select and I am not sure how to process that. I have a similar question answered here. But that is asked for using AND condition which works for me too. Here is my code
HTML
<ui-select ng-model="citySelected">
<ui-select-match>
{{$select.selected.name + ', ' + $select.selected.country}}
</ui-select-match>
<ui-select-choices repeat="city in List | filter: {name: $select.search} | orderBy:'sortOrder'">
<span ng-bind-html="city.name + ', ' + city.country| highlight: $select.search"></span>
</ui-select-choices>
</ui-select>
I am using a properties filter to search through any of the parameters that I have specified.
app.filter('propsFilter', function() {
return function(items, props) {
var out = [];
if (angular.isArray(items)) {
items.forEach(function(item) {
var itemMatches = false;
var keys = Object.keys(props);
for (var i = 0; i < keys.length; i++) {
var prop = keys[i];
var text = props[prop].toLowerCase();
if (item[prop].toString().toLowerCase().indexOf(text) !== -1){
itemMatches = true;
break;
}
}
if (itemMatches) {
out.push(item);
}
});
} else {
// Let the output be the input untouched
out = items;
}
return out;
}
});
//To use add this to UI-Selet Where you are using filter
<ui-select-choices repeat="city in List | propsFilter: {name: $select.search, secondFilter: $select.search, third: $select.search} | orderBy:'sortOrder'">

How to make ng-repeat filter out duplicate results

I'm running a simple ng-repeat over a JSON file and want to get category names. There are about 100 objects, each belonging to a category - but there are only about 6 categories.
My current code is this:
<select ng-model="orderProp" >
<option ng-repeat="place in places" value="{{place.category}}">{{place.category}}</option>
</select>
The output is 100 different options, mostly duplicates. How do I use Angular to check whether a {{place.category}} already exists, and not create an option if it's already there?
edit: In my javascript, $scope.places = JSON data, just to clarify
You could use the unique filter from AngularUI (source code available here: AngularUI unique filter) and use it directly in the ng-options (or ng-repeat).
<select ng-model="orderProp" ng-options="place.category for place in places | unique:'category'">
<option value="0">Default</option>
// unique options from the categories
</select>
Or you can write your own filter using lodash.
app.filter('unique', function() {
return function (arr, field) {
return _.uniq(arr, function(a) { return a[field]; });
};
});
You can use 'unique'(aliases: uniq) filter in angular.filter module
usage: colection | uniq: 'property'
you can also filter by nested properties: colection | uniq: 'property.nested_property'
What you can do, is something like that..
function MainController ($scope) {
$scope.orders = [
{ id:1, customer: { name: 'foo', id: 10 } },
{ id:2, customer: { name: 'bar', id: 20 } },
{ id:3, customer: { name: 'foo', id: 10 } },
{ id:4, customer: { name: 'bar', id: 20 } },
{ id:5, customer: { name: 'baz', id: 30 } },
];
}
HTML: We filter by customer id, i.e remove duplicate customers
<th>Customer list: </th>
<tr ng-repeat="order in orders | unique: 'customer.id'" >
<td> {{ order.customer.name }} , {{ order.customer.id }} </td>
</tr>
result
Customer list:
foo 10
bar 20
baz 30
this code works for me.
app.filter('unique', function() {
return function (arr, field) {
var o = {}, i, l = arr.length, r = [];
for(i=0; i<l;i+=1) {
o[arr[i][field]] = arr[i];
}
for(i in o) {
r.push(o[i]);
}
return r;
};
})
and then
var colors=$filter('unique')(items,"color");
If you want to list categories, I think you should explicitly state your
intention in the view.
<select ng-model="orderProp" >
<option ng-repeat="category in categories"
value="{{category}}">
{{category}}
</option>
</select>
in the controller:
$scope.categories = $scope.places.reduce(function(sum, place) {
if (sum.indexOf( place.category ) < 0) sum.push( place.category );
return sum;
}, []);
Here's a straightforward and generic example.
The filter:
sampleApp.filter('unique', function() {
// Take in the collection and which field
// should be unique
// We assume an array of objects here
// NOTE: We are skipping any object which
// contains a duplicated value for that
// particular key. Make sure this is what
// you want!
return function (arr, targetField) {
var values = [],
i,
unique,
l = arr.length,
results = [],
obj;
// Iterate over all objects in the array
// and collect all unique values
for( i = 0; i < arr.length; i++ ) {
obj = arr[i];
// check for uniqueness
unique = true;
for( v = 0; v < values.length; v++ ){
if( obj[targetField] == values[v] ){
unique = false;
}
}
// If this is indeed unique, add its
// value to our values and push
// it onto the returned array
if( unique ){
values.push( obj[targetField] );
results.push( obj );
}
}
return results;
};
})
The markup:
<div ng-repeat = "item in items | unique:'name'">
{{ item.name }}
</div>
<script src="your/filters.js"></script>
I decided to extend #thethakuri's answer to allow any depth for the unique member. Here's the code. This is for those who don't want to include the entire AngularUI module just for this functionality. If you're already using AngularUI, ignore this answer:
app.filter('unique', function() {
return function(collection, primaryKey) { //no need for secondary key
var output = [],
keys = [];
var splitKeys = primaryKey.split('.'); //split by period
angular.forEach(collection, function(item) {
var key = {};
angular.copy(item, key);
for(var i=0; i<splitKeys.length; i++){
key = key[splitKeys[i]]; //the beauty of loosely typed js :)
}
if(keys.indexOf(key) === -1) {
keys.push(key);
output.push(item);
}
});
return output;
};
});
Example
<div ng-repeat="item in items | unique : 'subitem.subitem.subitem.value'"></div>
I had an array of strings, not objects and i used this approach:
ng-repeat="name in names | unique"
with this filter:
angular.module('app').filter('unique', unique);
function unique(){
return function(arry){
Array.prototype.getUnique = function(){
var u = {}, a = [];
for(var i = 0, l = this.length; i < l; ++i){
if(u.hasOwnProperty(this[i])) {
continue;
}
a.push(this[i]);
u[this[i]] = 1;
}
return a;
};
if(arry === undefined || arry.length === 0){
return '';
}
else {
return arry.getUnique();
}
};
}
UPDATE
I was recomending the use of Set but sorry this doesn't work for ng-repeat, nor Map since ng-repeat only works with array. So ignore this answer. anyways if you need to filter out duplicates one way is as other has said using angular filters, here is the link for it to the getting started section.
Old answer
Yo can use the ECMAScript 2015 (ES6) standard Set Data structure, instead of an Array Data Structure this way you filter repeated values when adding to the Set. (Remember sets don't allow repeated values). Really easy to use:
var mySet = new Set();
mySet.add(1);
mySet.add(5);
mySet.add("some text");
var o = {a: 1, b: 2};
mySet.add(o);
mySet.has(1); // true
mySet.has(3); // false, 3 has not been added to the set
mySet.has(5); // true
mySet.has(Math.sqrt(25)); // true
mySet.has("Some Text".toLowerCase()); // true
mySet.has(o); // true
mySet.size; // 4
mySet.delete(5); // removes 5 from the set
mySet.has(5); // false, 5 has been removed
mySet.size; // 3, we just removed one value
It seems everybody is throwing their own version of the unique filter into the ring, so I'll do the same. Critique is very welcome.
angular.module('myFilters', [])
.filter('unique', function () {
return function (items, attr) {
var seen = {};
return items.filter(function (item) {
return (angular.isUndefined(attr) || !item.hasOwnProperty(attr))
? true
: seen[item[attr]] = !seen[item[attr]];
});
};
});
Here's a template-only way to do it (it's not maintaining the order, though). Plus, the result will be ordered as well, which is useful in most cases:
<select ng-model="orderProp" >
<option ng-repeat="place in places | orderBy:'category' as sortedPlaces" data-ng-if="sortedPlaces[$index-1].category != place.category" value="{{place.category}}">
{{place.category}}
</option>
</select>
None of the above filters fixed my issue so I had to copy the filter from official github doc. And then use it as explained in the above answers
angular.module('yourAppNameHere').filter('unique', function () {
return function (items, filterOn) {
if (filterOn === false) {
return items;
}
if ((filterOn || angular.isUndefined(filterOn)) && angular.isArray(items)) {
var hashCheck = {}, newItems = [];
var extractValueToCompare = function (item) {
if (angular.isObject(item) && angular.isString(filterOn)) {
return item[filterOn];
} else {
return item;
}
};
angular.forEach(items, function (item) {
var valueToCheck, isDuplicate = false;
for (var i = 0; i < newItems.length; i++) {
if (angular.equals(extractValueToCompare(newItems[i]), extractValueToCompare(item))) {
isDuplicate = true;
break;
}
}
if (!isDuplicate) {
newItems.push(item);
}
});
items = newItems;
}
return items;
};
});
If you want to get unique data based on the nested key:
app.filter('unique', function() {
return function(collection, primaryKey, secondaryKey) { //optional secondary key
var output = [],
keys = [];
angular.forEach(collection, function(item) {
var key;
secondaryKey === undefined ? key = item[primaryKey] : key = item[primaryKey][secondaryKey];
if(keys.indexOf(key) === -1) {
keys.push(key);
output.push(item);
}
});
return output;
};
});
Call it like this :
<div ng-repeat="notify in notifications | unique: 'firstlevel':'secondlevel'">
Add this filter:
app.filter('unique', function () {
return function ( collection, keyname) {
var output = [],
keys = []
found = [];
if (!keyname) {
angular.forEach(collection, function (row) {
var is_found = false;
angular.forEach(found, function (foundRow) {
if (foundRow == row) {
is_found = true;
}
});
if (is_found) { return; }
found.push(row);
output.push(row);
});
}
else {
angular.forEach(collection, function (row) {
var item = row[keyname];
if (item === null || item === undefined) return;
if (keys.indexOf(item) === -1) {
keys.push(item);
output.push(row);
}
});
}
return output;
};
});
Update your markup:
<select ng-model="orderProp" >
<option ng-repeat="place in places | unique" value="{{place.category}}">{{place.category}}</option>
</select>
This might be overkill, but it works for me.
Array.prototype.contains = function (item, prop) {
var arr = this.valueOf();
if (prop == undefined || prop == null) {
for (var i = 0; i < arr.length; i++) {
if (arr[i] == item) {
return true;
}
}
}
else {
for (var i = 0; i < arr.length; i++) {
if (arr[i][prop] == item) return true;
}
}
return false;
}
Array.prototype.distinct = function (prop) {
var arr = this.valueOf();
var ret = [];
for (var i = 0; i < arr.length; i++) {
if (!ret.contains(arr[i][prop], prop)) {
ret.push(arr[i]);
}
}
arr = [];
arr = ret;
return arr;
}
The distinct function depends on the contains function defined above. It can be called as array.distinct(prop); where prop is the property you want to be distinct.
So you could just say $scope.places.distinct("category");
Create your own array.
<select name="cmpPro" ng-model="test3.Product" ng-options="q for q in productArray track by q">
<option value="" >Plans</option>
</select>
productArray =[];
angular.forEach($scope.leadDetail, function(value,key){
var index = $scope.productArray.indexOf(value.Product);
if(index === -1)
{
$scope.productArray.push(value.Product);
}
});

AngularJS : Two-way binding between a textarea and ng-repeat-ed inputs

I was going to ask this as a question, but I figured out a solution. So at this point, I'm looking for a critique of my solution.
I've got a static textarea, and an input with an ng-repeat directive.
As the user types a sentence into the textarea, a input is rendered for each word in the sentence.
Then if the user updates the text in any input, the corresponding word in the textarea sentence is updated (really the whole sentence is recreated).
Demo: http://plnkr.co/edit/bSjtOK?p=preview
Questions
Keeping in mind that I'm only 2 weeks into my AngularJS learning:
Did I write this in the "angular" way?
Is there something I could have done better?
Am I violating any no-nos?
Abbreviated Code
HTML
<textarea ng-model="sentence" ng-change="parseSentence()" style="width: 100%; height: 15em;"></textarea>
<input type="text" ng-repeat="w in words" ng-model="w.word" ng-change="buildSentance(w)" />
JavaScript
function WordCtrl($scope, debounce) {
$scope.words = [];
$scope.sentence = 'Hello there how are you today?';
// this is called when the textarea is changed
// it splits up the textarea's text and updates $scope.words
$scope.parseSentence = function() {
var words = $scope.sentence.split(/\s+/g);
var wordObjects = [];
for (var i=0;i<words.length;i++) {
wordObjects.push({word: words[i]});
}
if ((words.length == 1) && (words[0] === '')) {
$scope.words = [];
} else {
$scope.words = wordObjects;
}
};
$scope.parseSentenceDebounced = debounce($scope.parseSentence, 1000, false);
$scope.buildSentance = function(w) {
var words = [];
for (var i=0;i<$scope.words.length;i++) {
var word = $scope.words[i].word;
if (word.replace(/\s+/g,'') !== '') {
words.push(word);
}
}
$scope.sentence = words.join(' ');
// if the user puts a space in the input
// call parseSentence() to update $scope.words
if (w.word.indexOf(' ') > -1) {
$scope.parseSentenceDebounced();
}
}
$scope.parseSentence();
}
Interesting issue you are having. I put your code on my page and the first thing I noticed is that you cannot pass debounce in the controller method.
Next Problem I noticed is that you have an ng-change that changes the values on another box with ng-change. I changed the event to Keypress to stop the digest in a digest.
Here it is working in JSFiddle enter link description here
The code:
HTML
<body ng-app="portal">
<div ng-controller="WordCtrl">
<textarea ng-model="sentence" ng-keypress="parseSentence()" style="width: 100%; height: 15em;"></textarea>
<input type="text" ng-repeat="w in words" ng-model="w.word" ng-keypress="buildSentance(w)" />
</div>
</body>
Javascript
angular.module("portal",[]).controller("WordCtrl",function($scope) {
$scope.words = [];
$scope.sentence = 'Hello there how are you today?';
$scope.parseSentence = function () {
var words = $scope.sentence.split(/\s+/g);
var wordObjects = [];
for (var i = 0; i < words.length; i++) {
wordObjects.push({ word: words[i] });
}
if ((words.length == 1) && (words[0] === ''))
{
$scope.words = [];
}
else
{
$scope.words = angular.copy(wordObjects);
}
}
$scope.buildSentance = function (w) {
var words = [];
for (var i = 0; i < $scope.words.length; i++) {
var word = $scope.words[i].word;
if (word.replace(/\s+/g, '') !== '') {
words.push(word);
}
}
$scope.sentence = words.join(' ');
// if the user puts a space in the input
// call parseSentence() to update $scope.words
if (w.word.indexOf(' ') > -1) {
$scope.parseSentenceDebounced();
}
}
$scope.parseSentence();
});
Hope this solves your issue.

Resources