Handlebars Reference two separate objects in the same line - javascript

I have a lookup object called Locations:
{
'CA:' 'California',
'NV': 'Nevada',
'FL': 'Florida',
...
}
and an array of addresses:
[
{street:'123 place', state:'FL', ...}
]
Is it possible to reference the output of a lookup in a handlebars template tag?
Something like this is what I've tried
{{#each addresses}}
{{Lookup[this.state]}}
{{/each}}
But I get an error. So i'm probably referencing Lookup wrong.

The lookup helper, in addition to being lower-case (not "Lookup"), takes two arguments separated by spaces. The first argument is the path to the object (or array) you want to do the lookup in and the second argument is the key to use. So in your case you probably want {{lookup ../locations this.state}}. Here it is in a snippet:
var source =
'{{#each addresses}}' +
'<li>{{lookup ../locations this.state}}</li>' +
'{{/each}}';
var template = Handlebars.compile(source);
var data = {
locations: {
'CA': 'California',
'NV': 'Nevada',
'FL': 'Florida',
// ...
},
addresses: [
{ street: '123 Place', state: 'FL' },
{ street: '456 Other', state: 'NV' },
{ street: '789 Last', state: 'CA' },
// ...
]
};
document.getElementById('list').innerHTML = template(data);
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.4/handlebars.js"></script>
<ul id="list"/>

Related

Assign array values to top level object javascript

At the bottom is a slimmed down version of a JSON file that I am trying to parse. I would like to create individual objects that have a key for the team name and the player name.
How would I go about using the team name and mapping to each individual player and receive something like this (using javascript):
[
{ name: 'Dallas Stars', playerName: 'Alexander Radulov'},
{ name: 'Dallas Stars', playerName: 'Ben Bishop'},
{ name: 'Dallas Stars', playerName: 'Jamie Benn'}
...
{ name: 'Columbus Blue Jackets', playerName: 'Pierre-Luc Dubois'}
]
From this JSON:
[ { name: 'Dallas Stars',
roster:
[ 'Alexander Radulov',
'Ben Bishop',
'Jamie Benn',
'Tyler Pitlick',
'Miro Heiskanen' ] },
{ name: 'Los Angeles Kings',
roster:
[ 'Jonathan Quick',
'Jonny Brodzinski',
'Oscar Fantenberg' ] },
{ name: 'San Jose Sharks',
roster:
[ 'Joe Thornton',
'Brent Burns',
'Joe Pavelski',
'Antti Suomela' ] },
{ name: 'Columbus Blue Jackets',
roster:
[ 'Sonny Milano',
'Brandon Dubinsky',
'Nick Foligno',
'Pierre-Luc Dubois' ] } ]
Essentially I am trying to map a top level key pair to individual players. I have tried searching through all lodash functions as well and haven't stumbled upon the correct way to do this.
Is there a way to use a flat map and have the team name used multiple times?
You need to iterate over the outer array items, and then inside of each of those, iterate over the roster too. reduce is usually the most appropriate method for transforming an array into another array on a non-one-to-one basis:
const input=[{name:'Dallas Stars',roster:['Alexander Radulov','Ben Bishop','Jamie Benn','Tyler Pitlick','Miro Heiskanen']},{name:'Los Angeles Kings',roster:['Jonathan Quick','Jonny Brodzinski','Oscar Fantenberg']},{name:'San Jose Sharks',roster:['Joe Thornton','Brent Burns','Joe Pavelski','Antti Suomela']},{name:'Columbus Blue Jackets',roster:['Sonny Milano','Brandon Dubinsky','Nick Foligno','Pierre-Luc Dubois']}];
const output = input.reduce((a, { name, roster }) => {
roster.forEach((playerName) => {
a.push({ name, playerName });
});
return a;
}, []);
console.log(output);
You can also use map and flat.
Map over the original array, then for each item being "mapped" map over its roster and create your desired object. Finally, since the resulting array will be 2d, flatten it:
var data = [{ name: 'Dallas Stars', roster: ['Alexander Radulov', 'Ben Bishop', 'Jamie Benn', 'Tyler Pitlick', 'Miro Heiskanen' ] }, { name: 'Los Angeles Kings', roster: ['Jonathan Quick', 'Jonny Brodzinski', 'Oscar Fantenberg' ] }, { name: 'San Jose Sharks', roster: ['Joe Thornton', 'Brent Burns', 'Joe Pavelski', 'Antti Suomela' ] }, { name: 'Columbus Blue Jackets', roster: ['Sonny Milano', 'Brandon Dubinsky', 'Nick Foligno', 'Pierre-Luc Dubois' ] } ];
var res = data
.map(({name, roster}) =>
roster.map(playerName => ({name, playerName})))
.flat();
console.log(res);

Access a key from SQL rows

I am pretty new to JavaScript and Mysql. MySQL query (which I have run in my server-side code in JS) returns rows in this form
i.e. console.log(rows) gives:-
[ RowDataPacket {
id: 7080,
post_author: 134,
post_title: '99 Varieties Dosa, Indira Nagar',
post_content: 'There',
link: '99-varieties-dosa-indira-nagar',
seo_keywords: null,
seo_desc: null,
seo_title: null,
best_for: 'Dosas',
special_info: '',
also_serves: 'Dosas',
'close-timing': '',
address: '56, 9th A Main Road',
direction_landmarks: 'Located in Indira Nagar',
seating: 'Unavailable',
longitude: '77.64097630979995',
latitude: '12.9777060556',
phone_no: ' ',
image_url: null,
location: 'Indira Nagar',
cuisine: 'South Indian Tiffin',
categories: 'Local Food',
Tags: 'Mysore Masala Dosa' }]
[ RowDataPacket {...}]
[ RowDataPacket {...}]
[ RowDataPacket {...}]
[ RowDataPacket {...}]
How can I access the location key of RowDataPacket Object?
I tried rows[i].location, rows[i]["location"], rows.location, rows[i].RowDataPacket.location etc.
When you are doing console.log(rows); you are getting data in the form of JSON array, which can be accessible using below code snippet:
$.each(rows, function(index, data){
// check your index & data details like below & perform other tasks
console.log('INDEX=', index);
consoel.log('DATA=', data); // Here data will be an object
// to access individual key data like location, you can try below code
console.log('LOCATION=', data.location);
});
For further reference you can go through link: https://api.jquery.com/each/

Making Angular Filter Dynamic in the controller

I've seen a couple other posts that I thought could help but haven't had any luck. I have a filter that is working fine when I statically specify what property I want to be filtering with. I am building an angular component where I don't know what data will actual be passed into the component. For example, here is some sample data:
this.customers = [
{ name: 'Jim', city: 'Minneapolis', state: 'MN', zip: 44332 },
{ name: 'Boe', city: 'Scottsdale', state: 'AZ', zip: 44332 },
{ name: 'Tom', city: 'S.F.', state: 'CA', zip: 11223 },
{ name: 'Joe', city: 'Dallas', state: 'TX', zip: 34543 },
{ name: 'Jon', city: 'L.A.', state: 'CA', zip: 56433 }
];
My static filters work great:
public filterTextChangeLocal($event: ng.IAngularEvent) {
if (this.itemDisplayProperty = "name") {
this.filteredItems = this.$filter("filter")(this.items, {name: this.ngModelValue});
} else if (this.itemDisplayProperty = "city") {
this.filteredItems = this.$filter("filter")(this.items, {city: this.ngModelValue});
} else if (this.itemDisplayProperty = "state") {
this.filteredItems = this.$filter("filter")(this.items, {state: this.ngModelValue});
} else if (this.itemDisplayProperty === "zip") {
this.filteredItems = this.$filter("filter")(this.items, {zip: this.ngModelValue});
}
}
The problem is the user of the component may pass in any type of data, with properties that may be completely different so I need something that can account for any property specified. I have an isolate scope property called "itemDisplayProperty" that allows the user to specify which property from their data they want to show in the dropdown, and that is the property that I need to be filtered. They could say, "item-display-property="address", the data in the address property would be displayed in the dropdown. I tried this but doesn't work as multiple "this" words aren't allowed:
this.filteredItems = this.$filter("filter")(this.items, {
this.itemDisplayProperty : this.ngModelValue
});
Here's my input and dropdown for reference:
<input type="text" class="form-control"
ng-change="ctrl.filterTextChangeLocal($event)"
ng-model="ctrl.ngModelValue"
ng-click="ctrl.openDropdown($event)" />
<ul class="dropdown-menu list-group" ng-if="!ctrl.ngDisabled">
<li class="list-group-item"
ng-repeat="row in ctrl.filteredItems"
ng-mousedown="ctrl.onSelectedLocal(row, $event)">
{{row[ctrl.itemDisplayProperty]}}
</li>
</ul>
In order to refactor the static filters inside filterTextChangeLocal all that you need to do is construct a $filter expression with a dynamic key.
This can be achieved by using the so called bracket notation:
var obj = {};
obj[myKey] = value;
The refactored filterTextChangeLocal would look something like this:
public filterTextChangeLocal($event: ng.IAngularEvent) {
var filterExpression = {};
filterExpression[this.itemDisplayProperty] = this.ngModelValue;
this.filteredItems = this.$filter("filter")(this.items, filterExpression);
}
I solved my own question this way, appears to be a new ES6 way to use a variable inside an object. The marked answer would have worked as well:
this.filteredItems = this.$filter("filter")(this.items, {[this.itemDisplayProperty] : this.ngModelValue});
OK, that's right, with ES6 you can use computed proporties.
With ES5 you could create a filter object like this (with var self=this; in your controller):
var filterObj = {};
filterObj[self.itemDisplayProperty] = self.ngModelValue;
self.filteredItems = $filter("filter")(self.items, filterObj);
Please have a look at the demo below or this jsfiddle.
Just a note to your variable names. Avoid ng prefix in your names (e.g. ngDisabled in your code). Because this variable has nothing to do with AngularJs and a different name will make your code more readable. Something like showDrop would be better.
angular.module('demoApp', [])
.controller('mainController', MainController)
.directive('dynFilter', DynFilterDirective);
function DynFilterDirective($filter) {
return {
restrict: 'E',
controllerAs: 'ctrl',
templateUrl: 'components/dynFilterTempl.html',
bindToController: {
items: '=',
itemDisplayProperty: '='
},
scope: {},
controller: function() {
var self = this;
self.filterTextChangeLocal = function($event) {
var filterObj = {};
filterObj[self.itemDisplayProperty] = self.ngModelValue;
console.log(filterObj);
self.filteredItems = $filter("filter")(self.items, filterObj);
};
}
}
}
function MainController($filter) {
var vm = this;
vm.items = [
{ name: 'Jim', city: 'Minneapolis', state: 'MN', zip: 44332 },
{ name: 'Boe', city: 'Scottsdale', state: 'AZ', zip: 44332 },
{ name: 'Tom', city: 'S.F.', state: 'CA', zip: 11223 },
{ name: 'Joe', city: 'Dallas', state: 'TX', zip: 34543 },
{ name: 'Jon', city: 'L.A.', state: 'CA', zip: 56433 },
];
vm.keys = Object.keys(vm.items[0]);
vm.curProp = vm.keys[0];
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.4/angular.js"></script>
<div ng-app="demoApp" ng-controller="mainController as mainCtrl">
{{Object.keys(mainCtrl.items[0])}}
Choose your filter: <select ng-options="prop for prop in mainCtrl.keys" ng-model="mainCtrl.curProp"></select>
<dyn-filter item-display-property="mainCtrl.curProp" items="mainCtrl.items"></dyn-filter>
<script type="text/ng-template" id="components/dynFilterTempl.html">
<input type="text" class="form-control" ng-change="ctrl.filterTextChangeLocal($event)"
ng-model="ctrl.ngModelValue" ng-focus="ctrl.showDrop = true" ng-blur="ctrl.showDrop = false" />
<ul class="dropdown-menu list-group" ng-show="ctrl.showDrop">
<li class="list-group-item" ng-repeat="row in ctrl.filteredItems"
ng-mousedown="ctrl.onSelectedLocal(row, $event)">
{{row[ctrl.itemDisplayProperty]}}
</li>
</ul>
</script>
</div>

twitter type head rails not working

I'm using the https://github.com/yourabi/twitter-typeahead-rails gem but the text_field does nothing. I removed //= require turbolinks from application.js to see if that had anything to do with it.
new.html.erb
<script>
var substringMatcher = function(strs) {
return function findMatches(q, cb) {
var matches, substringRegex;
// an array that will be populated with substring matches
matches = [];
// regex used to determine if a string contains the substring `q`
substrRegex = new RegExp(q, 'i');
// iterate through the pool of strings and for any string that
// contains the substring `q`, add it to the `matches` array
$.each(strs, function(i, str) {
if (substrRegex.test(str)) {
// the typeahead jQuery plugin expects suggestions to a
// JavaScript object, refer to typeahead docs for more info
matches.push({ value: str });
}
});
cb(matches);
};
};
var states = ['Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California',
'Colorado', 'Connecticut', 'Delaware', 'Florida', 'Georgia', 'Hawaii',
'Idaho', 'Illinois ];
$('#thebasics').typeahead({
hint: true,
highlight: true,
minLength: 1
},
{
name: 'states',
displayKey: 'value',
source: substringMatcher(states)
});
</script>
<%= f.text_field :school, :id => "thebasics", :class => "fr-input", :placeholder => "states" %>
what am I missing?
I think it is the script not running because I tried
First, fix your missing apostrophe after Illinois.
Second, your typeahead needs something to initialize it. Try calling it in $(document).ready and it will work fine as long as you have the Typeahead files included in your asset pipeline. I'd move your JS to a separate instead of having it in your view. This is how I tested it and it worked.
yourSearch.js:
var substringMatcher = function (strs) {
return function findMatches(q, cb) {
var matches, substringRegex;
// an array that will be populated with substring matches
matches = [];
// regex used to determine if a string contains the substring `q`
substrRegex = new RegExp(q, 'i');
// iterate through the pool of strings and for any string that
// contains the substring `q`, add it to the `matches` array
$.each(strs, function (i, str) {
if (substrRegex.test(str)) {
// the typeahead jQuery plugin expects suggestions to a
// JavaScript object, refer to typeahead docs for more info
matches.push({
value: str
});
}
});
cb(matches);
};
};
var states = ['Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California',
'Colorado', 'Connecticut', 'Delaware', 'Florida', 'Georgia', 'Hawaii',
'Idaho', 'Illinois' ];
$(document).ready(function(){
$('#thebasics').typeahead({
hint: true,
highlight: true,
minLength: 1
},
{
name: 'states',
displayKey: 'value',
source: substringMatcher(states)
});
});
Make sure that is loaded into your asset pipeline along with the Typeahead source files.

How to parse below JSON

How to parse below JSON code in JavaScript where iterators are not identical?
var js= {
'7413_7765': {
availableColorIds: [ '100', '200' ],
listPrice: '$69.00',
marketingMessage: '',
prdId: '7413_7765',
prdName: 'DV by Dolce Vita Archer Sandal',
rating: 0,
salePrice: '$59.99',
styleId: '7765'
},
'0417_2898': {
availableColorIds: [ '249', '203' ],
listPrice: '$24.95',
marketingMessage: '',
prdId: '0417_2898',
prdName: 'AEO Embossed Flip-Flop',
rating: 4.5,
salePrice: '$19.99',
styleId: '2898'
},
prod6169041: {
availableColorIds: [ '001', '013', '800' ],
listPrice: '$89.95',
marketingMessage: '',
prdId: 'prod6169041',
prdName: 'Birkenstock Gizeh Sandal',
rating: 5,
salePrice: '$79.99',
styleId: '7730'
}
}
How can I parse this JSON in JavaScript? I want the values of prdName, listprice, salePrice in JavaScript?
var products = js; // more semantic
for (productId in products){
var product = products[productId];
console.log (product.prdName , product.listprice, product.salePrice);
}
js is an Object, the for (key in instance) iteration moves through the first level object's attributes, in this case 7413_7765, 0417_2898 and prod6169041, this keys are stored in the var productId, so products[productId] will return the value of this attributes.
Note that the "" in object keynames are not necesary.
You have already assigned the JSON to an object js.
You're trying to loop through JavaScript object, as Edorka mentioned iterate it.

Categories