I am looping through an array and displaying the search results if the result is either a "place" or "address". Here is the current output -
How to group all the items matching the first condition and all the items matching the second conditions like this -
Can anyone please help. Below is my code. Places should display first and next addresses
predictions.forEach(function(prediction) {
if(prediction.types.indexOf("postal_code")){
console.log(prediction.types)
results_html.push(`<h3>Places</h3><li class="autocomplete-item" data-type="place" data-place-id=${prediction.place_id}><span class="autocomplete-icon icon-localities"></span>
<span class="autocomplete-text">${prediction.description}</span></li>`);
}else if(prediction.types.indexOf("address")){
console.log(prediction.types)
results_html.push(`<h3>Address</h3><li class="autocomplete-item" data-type="place" data-place-id=${prediction.place_id}><span class="autocomplete-icon icon-localities"></span>
<span class="autocomplete-text">${prediction.description}</span></li>`);
}
});
Push them to separate arrays and then combine them later:
results_places = [];
results_addresses = [];
predictions.forEach(function(prediction) {
if (prediction.types.indexOf("postal_code")) {
console.log(prediction.types)
results_places.push(`<li class="autocomplete-item" data-type="place" data-place-id=${prediction.place_id}><span class="autocomplete-icon icon-localities"></span>
<span class="autocomplete-text">${prediction.description}</span></li>`);
} else if (prediction.types.indexOf("address")) {
console.log(prediction.types)
results_addresses.push(`<li class="autocomplete-item" data-type="place" data-place-id=${prediction.place_id}><span class="autocomplete-icon icon-localities"></span>
<span class="autocomplete-text">${prediction.description}</span></li>`);
}
});
if (results_places.length) results_places.shift('<h3>Places</h3>');
if (results_addresses.length) results_addresses.shift('<h3>Address</h3>');
results_html = results_places.concat(results_addresses)
Related
I'm using Angularjs 1.4.2 and I have to create a drop down list that is a combination of numbers and text. It is an array of objects with two properties. So I use numbers as a type of label and convert the 0 value and the -1 values to text as the top and bottom of the list.
The reason I don't just hard code the text is inside the filter we call a service to change the language of the text for the page, which makes it dynamic for switching languages and hence the reason I opted for a number labeling system for the option entries.
However, I keep getting a blank option in the list and the default "Select Item" text for 0 cannot get pre-selected when the drop down appears.
What I found was that
the empty option is generated when a value referenced by ng-model
doesn't exist in a set of options passed to ng-options
In this case, the original list that was put in scope
has been modified by the filter, so I assume that is why the empty option appears in the drop down list.
My code works fine without the filter, but when I try to apply the filter, I get this error:
Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
The drop down list does have the correct values from the filter, but the empty option is still there and it is selected instead of the text "Select Item", which is what I want.
HTML:
<!DOCTYPE html>
<html ng-app="app">
<head>
<script data-require="angular.js#1.4.2" data-semver="1.4.2" src="https://code.angularjs.org/1.4.2/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body>
<div ng-controller="Test">
<p>selected item is : {{selectedItem}}</p>
<p> The distance of selected item is : {{selectedItem.distance}} </p>
<select ng-model="selectedItem" ng-options="item.distanceSize for item in items | myFilter" ng-init="selectedItem = items[0]">
</select>
</div>
</body>
</html>
script.js
var app = angular.module('app',[]);
app.controller('Test',function($scope){
$scope.items = [{"distance": "0", "distanceSize": 0},{"distance": "25", "distanceSize": 25},{"distance": "50", "distanceSize": 50},{"distance": "-1", "distanceSize": -1}];
});
app.filter('myFilter', function () {
return function (items) {
var valuesArray = [];
if(items) {
for(var i = 0; i < items.length; i++) {
var myObject = {};
if(items[i].distanceSize === 0) {
myObject.distanceLabel = "0";
myObject.distanceSize = "Select Item";
valuesArray.push(myObject);
}else if(items[i].distanceSize == 25) {
myObject.distanceLabel = "25";
myObject.distanceSize = 25;
valuesArray.push(myObject);
}
else if(items[i].distanceSize == 50) {
myObject.distanceLabel = "50";
myObject.distanceSize = 50;
valuesArray.push(myObject);
}
else if(items[i].distanceSize == -1) {
myObject.distanceLabel = "-1";
myObject.distanceSize = "Select Everything";
valuesArray.push(myObject);
}
}
}
return valuesArray;
};
});
Since my drop down list is modified by the filter, how to I remove or mask the empty option and why is the filter throwing errors?
10 $digest() iterations reached. Aborting!
This is a well known issue. I'd refer to this Stack Overflow question: How to Troubleshoot Angular “10 $digest() iterations reached” Error, specifically its answer about returning new objects. Every time angular calls myFilter it gets a new valuesArray that does not === the old valuesArray. Angular sees this as a change and calls the filter again and again, until it aborts with the error.
Rather than applying your filter to the entire array, apply the filter to the label. This changes your ng-options from:
ng-options="item.distanceSize for item in items | myFilter"
to
ng-options="item as (item.distanceSize | myFilter) for item in items"
Then change your filter to handle a single item:
app.filter('myFilter', function () {
return function (distanceSize) {
if (distanceSize === 0)
return "Select Item";
if (distanceSize === -1)
return "Select Everything";
return distanceSize;
}
});
You can see an example in this plunker.
The empty option is present because $scope.selectedItem is a null value. You can either set it to a default value (like I did in the plunker) or you can hard code a single element, with the value set to an empty string. This element will then represent the null or "not selected" option. This could replace your "Select Item" option. You can find more information about this in the ngOptions documentation.
I'm trying to show a stock message whether the item has enough quantity in the API object for the user to add the right amount of quantity in the basket. Managed to do it with single item but since the items in the basket is an Array having an issue to show the stock message on the right item index in ng-repeat
HTML template code : --
<div ng-repeat="item in vm.basketList">
...
<button ng-click="vm.update(item)">Update qty</button>
// stock message
<span ng-if="vm.checkStock == false" class="text-warning">Stock is not enough.</span>
</div>
controller update qty: --
vm.update = function (item) {
// Will be needing this var for later
var updateCartItem = {
....
Products: [item]
}
// Date required for HTTP stock check
var xd = {
...
ProductIds: [updateCartItem.Products[0].product_idField]
}
itemService.itemStock(xd)
.then(function (response) {
console.log('Checking stock...');
for (var i = 0; i < response.data.Results.length; i++) {
var stockElement = response.data.Results[i];
if (stockElement.qtyField >= updateCartItem.Products[0].qtyField) {
console.log('Stock is enough go ahead update QTY');
vm.checkStock = true;
} else {
console.log('Stock is not enough');
vm.checkStock = false;
}
}
}
Here's an image of I'm trying to achieve, I marked them as cross and check (cross = not enough stock, check = enough stock so to update). So message not enough stock should only show on the item with cross.
My question is how do I show the message in the correct index for item that doesn't have enough stock, when I click the button to update the qty?
Hope this question make sense to some and would be able to answer.
have checkStock property on item.
vm.checkStock = false;
// make this
item.checkStock = false
In repeater
<span ng-if="vm.checkStock == false" class="text-warning">Stock is not enough.</span>
Change this to
<span ng-if="item.checkStock == false" class="text-warning">Stock is not enough.</span>
This code doesn't work
var next = $("#orders").find(".next");
if (next.length == 1) {
var address = $(next[0]).find(".directionsAddress");
var destination = $(address[0]).text();
}
<div id="orders" class="ui-sortable">
<div id="companyAddress" class="noDisplay">101 Billerica Avenue, North Billerica, MA</div>
<div id="companyPhone" class="noDisplay">9788353181</div><div class="next"></div>
<div class="lat">42.616007</div>
<div class="lng">-71.31187</div>
<div id="section1611" class="sectionMargin borderRad">
<div class="directionsAddress noDisplay">92+Swan+Street+Lowell+MA</div>
It is suppose to find one div with a class of "next" that I know exists on the page, then within that one item of the result set array, there will be one div with a class name of directionsAddress.
The "next" array is coming back with a length of 1, so it looks like the problem is with my $(next[0]).find because the address array is coming back as 0 length and I am making a syntax error of some sort that I don't understand.
This should do what you want. You need to find the parent (or alternatively, the sibling of .next) then try to find the applicable .directionsAddress.
var next = $("#orders").find(".next");
if (next.length == 1) {
var destination = $(next).parent().find(".directionsAddress");
alert($(destination).text());
}
Working fiddle: https://jsfiddle.net/00fgpv6L/
I've got a todo list. Each row has a star icon that you can click, exactly like gmail. The difference here is that if you click a star it should sort to the top (higher priority), but also re-sort within the starred group by ascending alpha. Unstarred items sort below, also sorted by ascending alpha. Everything is working as expected except for the alpha sorting. Below is the sort function where I'm doing that. I've verified that everything works below except the //sort the arrays by alpha bit...
Sort fail:
function sortTasks(currList) {
var starredTasks = [];
var unstarredTasks = [];
//create arrays
$('li.task').each(function(){
if ($(this).children('img.star').attr('src') == "images/star_checked.gif") {
starredTasks.push($(this));
} else {
unstarredTasks.push($(this));
}
});
//sort the arrays by alpha
starredTasks.sort( function(a,b){ ($(a).children('p.task-name').text().toUpperCase() > $(b).children('p.task-name').text().toUpperCase()) ? 1 : -1;});
unstarredTasks.sort( function(a,b){ ($(a).children('p.task-name').text().toUpperCase() > $(b).children('p.task-name').text().toUpperCase()) ? 1 : -1;});
//draw rows starred first, unstarred second
$(currList).empty();
for (i=0; i < starredTasks.length; i++) {
$(currList).append(starredTasks[i]);
}
for (i=0; i < unstarredTasks.length; i++) {
$(currList).append(unstarredTasks[i]);
}
}
This array has been populated with the task rows in the order they were originally drawn. The data renders fine, but basically stays in the same order.
Example task row:
<div id="task-container" class="container">
<form name="enter-task" method="post" action="">
<input id="new-task" name="new-task" type="text" autofocus>
</form>
<h2 id="today">today</h2>
<ul id="today-list">
<li id="457" class="task">
<img class="star" src="images/star_checked.gif">
<p class="task-name" contenteditable>buy milk</p>
<p class="task-date"> - Wednesday</p>
</li>
</ul>
<h2 id="tomorrow">tomorrow</h2>
<ul id="tomorrow-list">
</ul>
<h2 id="future">future</h2>
<ul id="future-list">
</ul>
<h2 id="whenever">whenever</h2>
<ul id="whenever-list">
</ul>
</div>
Each item in the starredTasks array is an entire task row. I'm assuming that $(a) is the same level as $(li)?
and here's the function that triggers the sort:
$('body').on('click', 'img.star', function(){
var thisList = '#' + $(this).parent('li').parent('ul').attr('id');
if ($(this).attr('src') == 'images/star_checked.gif') {
$(this).attr('src', 'images/star_unchecked.gif');
} else {
$(this).attr('src', 'images/star_checked.gif');
}
sortTasks(thisList);
});
Also, I doubt it's worth mentioning, but the data is stored in mySQL and prepopulated via php.
I wasn't sure of a way to use .sort() directly on the $('li') without splitting it into separate arrays...
Anybody see my goof?
I don't see where you're adding the sorted list back into the DOM. If you're not, then that's the problem. Sorting an array of elements doesn't update the DOM at all.
Furthermore, your sorting is very expensive. It's better to map an array of objects that have the elements paired with the actual values to sort.
Finally, you appear to be using the same ID multiple times on a page. That's just wrong. it may work with jQuery's .children(selector) filter, but it's still wrong. You need to change that.
Here I map an array of objects that contain a text property holding the text to sort and a task property that holds the element.
I changed p#task-name to p.task-name, so you should change that to class="task-name" on the elements.
Then I do the sort using .localeCompare(), which returns a numeric value.
Finally, the .forEach() loop appends the elements to the DOM.
var data = starredTasks.map(function(t) {
return { task: t,
text: $(t).children('p.task-name').text().toUpperCase()
};
}).sort(function(obj_a, obj_b) {
obj_a.text.localeCompare(obj_b.text);
}).forEach(function(obj) {
original_container.append(obj.task);
});
This assumes starredTasks is an actual Array. If it's a jQuery object, then do starredTasks.toArray().map(func....
The original_container represents a jQuery object that is the direct parent of the task elements.
I was wondering how I would go about finding and replacing some text in a div, but i want to find and replace the second occurrence of that text. For example:"You just added a item, please remove this item" so I would like to find the second "item" and replace it with whatever text I choose.
JS:
var compareCount = $('.compareWidget').find('.compareItem').length;
if (compareCount >= 2) {
$('.message').find('.count').text(compareCount);
$('message').html().replace('item', 'items');
}
$('.message').slideDown("Fast");
setTimeout(function () {
$('.message').slideUp("Fast");
}, 5000);
HTML:
<div id="alertMessage">
<div class="message">
<span>You just added a item to compare, you currently have <span class="count">1</span> item to compare</span>
</div>
</div>
"you currently have 1 item to compare"
You want to turn item to items?
You can do it with regular expressions, or you can wrap it into an element and grab that.
<span class="count">1</span> <span class="type">item</span> to compare</span>
and
$('.message').find('.type').text("items");
Using regular expressions you can
function replaceMatch(originalString, searchFor , replaceWith, matchNumber)
{
var match = 0;
return originalString.replace(searchFor, function(found){
match++;
return (match===matchNumber)?replaceWith:found;
},'g');
}
and call it like
var msg = $('.message');
msg.html( replaceMatch( msg.html(), 'item', 'items', 2) );
demo http://jsfiddle.net/gaby/crhvA/