AngularJS soltuion to determining if any element in array1 exists in array2 - javascript

I am working on an angularJS widget (my first) and I currently am looking for an angularJS solution to my problem.
Basically I have one array containing a list of string values.
var array1 = [
"Need to Know",
"Test Category 2",
"News"
];
and another array containing another list of string values
var array2 = [
"need to know",
"release notes",
"NEWS"
];
I need a true statement if any element from one array matches any element from the other array. The result also needs to be case insensitive.
Here is my current solution and works great.
angular.module("myWidget", function(...){
// angular code here
})
.service('arrayService', function() {
function arrayToLowerCase(array) {
return array.join("~!~").toLowerCase().split("~!~");
}
function arrayElementIsInArray(array1, array2) {
for (var i in array1) {
if (array2.indexOf(array1[i]) >= 0) {
return true;
}
}
return false;
}
function arrayCompare(array1, array2) {
return arrayElementIsInArray(arrayToLowerCase(array1), arrayToLowerCase(array2));
}
return {
arrayToLowerCase: arrayToLowerCase,
arrayElementIsInArray: arrayElementIsInArray,
arrayCompare: arrayCompare
};
})
the problem is my javascript coders (I primary work in c#) feel there is a more angularJS way to do this but they have brought nothing to the table as a definitive solution. It was suggested that the $filter module might be useful but I didn't see how it would exactly solve my problem.
If I already have the best solution, then awesome. If not please let me know what you think and lets go from there.
Thanks in advance.
EDIT: In response to some of the answers, I felt that I might have misinterpreted my request. What I am asking is there a built in function that angular provides that does this out of the box?
After researching this a bit more; the $filter Module will probably do it with a custom comparater implemented but that seems like way overkill for what I am looking for.
The current responses are all good stuff though. Thanks again!

Absolutely nothing to do with Angular. This is plain data structures and data manipulation. To say there should be a more AngularJS way of doing it would be like saying there should be a more MVC way to add two numbers.
Angular provides no basic data structures and utility set of functions beyond what is available in your browser's native list of array functions, which is different depending on which ECMAScript standard the browser supports.
You may want to look into a library like Lo-Dash for stuff like this (which you can use right along with Angular with no problems) as it's preferable to have proven code for these kind of data manipulations than to constantly have to debug your own.
With Lo-Dash, and remembering the requirement for case-insensitivity:
var array1Lowered = _.map(array1, function (value) { return value.toLowerCase(); });
var anyMatchesBool = _.any(array2, function (value) {
return _.contains(array1Lowered, value);
});
Note that I'm making the assumption that there will be no non-string items in either array.
Lo-Dash normalizes the API so you don't need to worry about what functions each browswer supports. If there's a native function, Lo-Dash will use it because it's faster. If not, Lo-Dash provides an all-JavaScript implementation.

Try this on for size. To me this really has nothing to do with Angular
(function(array1, array2) {
var tlc = function(a) { return a.toLowerCase(); };
array2 = array2.map(tlc);
array1 = array1.map(tlc);
return array1.filter(function(n) {
return array2.indexOf(n) != -1;
}).length > 0;
})(array1, array2);

Using native functions...
var intersection = array1.filter(function(n) {
return array2.indexOf(n) != -1
});
With help from Simplest code for array intersection in javascript

Related

How to convert object into array in angularjs Ionic

Let's say I have an object that looks like this: {first: "asdasd", second: "asdas", third: "dasdas", four: "sdasa"}
I need to convert this object into array.
if(values){
var first=values.first;
var second=values.second;
var third=values.third;
var four=values.four;
var five=values.five;
var six=values.six;
var seven=values.seven;
var eight=values.eight;
var nine=values.nine;
var ten=values.ten;
if(first){
userData.push(first);
}
if(second){
userData.push(second);
}
if(third){
userData.push(third);
}
if(four){
userData.push(four);
}
if(five){
userData.push(five);
}
if(six){
userData.push(six);
}
if(seven){
userData.push(seven);
}
if(eight){
userData.push(eight);
}
if(nine){
userData.push(nine);
}
if(ten){
userData.push(ten);
}
console.log(userData);
I am currently doing by this code but i think it is the wrong approach. So how could i change this to array that looks like ["asdasd", "asdas", "dasdas", "sdasa", "asdasd", "asdas", "dasdas", "sdasa"].
In ionic drag and drop directive doesnot work when i use object in ng-repeat.And works perfectly when i apply array to ng-repeat.
There are several ways you could do it.
One would be using Object.keys:
Object.keys(values).forEach(function(key) {
userData.push(values[key]);
});
You could also use for ... in like this:
for (var key in values) {
userData.push(value[key]);
}
If your object has any properties inherited from prototype then it would also show, so you do need to check if property really belongs to this instance:
for (var key in values) { //proper way to iterate keys using for..in
if(values.hasOwnProperty(key)) {
userData.push(value[key]);
}
}
Since you're using angular, you could also use angular.forEach:
angular.forEach(values, function(value){
userData.push(value);
});
and I think this is the cleanest solution for you.
I would suggest using javascript library underscorejs or lodash for this kind of array and objects manipulation and iteration ,as it seems to be most preferable way of doing it ,keeping your code clean.
Its a simple javascript file that you can include in your project and you don't have to do any complex thing to make it work.Just plug and play.
If you do include underscore/lodash ,all you have to do is :-
var mycoll = _.values(yourobjectvariable);
This will fetch all the values in that object and convert it into an array automatically for you.
http://underscorejs.org/#values
Or if you want to do it with plain javascript , i think the above Randall Flag's answer is suffice for it.
`
if(values)
{
Object.keys(values).forEach(function(key) {
userData.push(values[key]);
});
}
`
Sometimes instead of a simple solution we think too much and end up with complex time taking solution ,which we can achieve with small simple code

Best practice- when return in JS function

it happened to me multiple times that I face situation where I wasnt sure how I should stop function when I know result.
Just for example lets imagine we have object category which looks like:
{
"name": "CategoryName",
"subCategoriess": [{
"name": "Sub1",
"value": true
}, {
"name": "Sub2",
"value": false
}]
}
and we want to iterate over it until we found value === true
Clasic option (let's call it: Option 1)which i found in most documentation is:
function myFunction(category){
var ret = false;
for (var i=0; i <category.subCategoriess.length; i++)
{
ret = category.subCategories[i].value;
if (ret)
break;
}
return ret;
}
I alternativly saw something like this (let's call it: Option 2):
function myFunction(category){
for (var i=0; i <category.subCategoriess.length; i++)
{
if (category.subCategories[i].value) return true;
}
return false;
}
So let's compare this two options, i consider my self as junior so I may be wrong really easy so please do not hesitate to tell me that
Option 1 - Advantage of this option is that even if your code is more complicated you always know which return actualy "return" the function and I expect it may be easier for debug for many of us.
Option 2 - Advantage of this option is that it should use less performance becuase it doesnt need aditional variabile (ret) + we basicly avoid atleast one step where we break a for loop and going to actual return statment
In this particular example the differenc between each option is something really close to 0. But code can get more complicated so may I ask you guys what option is best practice (or if I miss something please add your option) and why it should be used like this?
There is more then just two options and it comes down to this:
Which do you (or your team) find is more comprehensible with the lowest cognitive load to read?
Some find procedural code easier. Some attempt to lower temp variables by returning early. Still some find a functional approach better:
return subject.collection.some(function (item) {
return !!item.value;
});
So it comes down to your team and your own cognitive preferences. The true take away is be consistent in your project. If you start with one style and find you like a new style note this in the README and maybe convert old styles as you see them.
The only answer to this question is: it depends (on code complexity)
Generally speaking, multiple return statement could make debugging a bit harder, but sometimes it is worth it.
In your example I'd probably go for the second option if I'd be sure that this method would only return true/false value.
But if I'd like to extend it's functionality in the future (fetch the record which fulfills the condition or get all the values that fulfill it) it may be easier to go for the first option.
I'd say option 2 because you don't need any intermediary variable to store the result, and the intent is clearer since you return immediately as soon as you can.
You can also improve legibility and performance (a bit) by storing each item as you iterate.
for (var i = 0, item; item = category.subCategoriess[i]; i++) {
if (item.value) return true;
}
return false;
How about Option 3?
Using Array.some gives you the best of both worlds as it doesn't require a break or multiple return statements.
var category = {
"name": "CategoryName",
"subCategoriess": [{
"name": "Sub1",
"value": true
}, {
"name": "Sub2",
"value": false
}]
}
function myFunction(category){
var result = category.subCategoriess.some(function(subCategory) {
return subCategory.value;
});
return result;
}
console.log(myFunction(category))

Can this javascript be reduced?

I was curious to see if anyone knew a of a way to reduce this javascript code:
var channels;
channels = [];
$('li.suggestions article').each(function() {
return channels.push($(this).data('channel-id'));
});
It's really simple -- the snippet just initializes an array called "channels", iterates over some DOM elements and collects their "data-channel-id" attribute, adding it to that array.
It is something I do a lot and it would be great to have this snippet simplified further -- I'd accept a CoffeeScript answer too if there is a nice solution.
var channels = $('li.suggestions article').map(function() {
return $(this).data('channel-id');
}).get();

Creating and implementing an array from space delimited text: AngularJS

and thank you for your patience. I am an experienced coder using old school methods, and have used the old style of Javascript for many years. I've known about JQuery, and such as that for a while, but have been "too busy" to learn the new things. Well, I am now working on learning those things, and have chosen AngularJS.
I am watching the tutorial videos, and reading the documents and API reference for AngularJS, but the different nomenclature does impede my progress. But I'm trying. For me, using an example of a "real" sort of problem helps me to understand how to leverage the functionality.
In this example, I have an array of Power Ball numbers, and want to be able to paste in the space delimited winning numbers you might copy off of the Power Ball site. This would then parse the input and hi-lite all of the individual numbers. Eventually, perhaps hi-liting any winning combinations in different ways. No, this isn't a product I'm building, but I thought this would cause me to use many different tools in this tool box.
So my questions are:
I initialized the array in my service (factory) and have shown that I can push to it from my controller. Is this correct?
Is my current way of doing things (e.g. ng-class usage, etc.) at least feasible, if not correct?
How could I use space delimited input in the input/text box to do the comparison for the style changes?
Here is an example of my JavaScript code. (note: I'm only pasting in one set of numbers for the array.)
var lotteryCheckApp = angular.module('lotteryCheckApp', []);
lotteryCheckApp.factory('PowerBall', function() {
var PowerBall = {};
PowerBall.numArray = ["42"];
PowerBall.myNumbers = [
{
First_Number: '03',
Second_Number: '07',
Third_Number: '17',
Fourth_Number: '21',
Fifth_Number: '42',
PowerBall: '21'
}
];
return PowerBall;
});
lotteryCheckApp.controller('PowerBallNumbersCtrl',function($scope,PowerBall) {
$scope.powerball = PowerBall;
$scope.winningStyle = true;
$scope.powerball.numArray.push("21");
$scope.myCheck = function(searchNum,numVal) {
// the following code works for a simple input to value check
if(searchNum == numVal) return true;
else return false;
}
I have a JSFiddle link: http://jsfiddle.net/Divermarv/VpyxZ/1/
Again, thank you all for your patience and responses.
Glad to hear you're getting into angular. Here is how I would solve your problem JSFiddle
I use ng-change to watch the input values,
<input type="text" ng-model="input" ng-change="convert()">
and feed that to a method that converts the input to an array of values.
$scope.convert = function() {
$scope.hiLite = $scope.input.split(" ");
}
Then your check function checks to see if the value is in the array
$scope.myCheck = function(searchNum,numVal) {
if(searchNum.indexOf(numVal) !== -1) return true;
else return false;
}
Is that kind of what you were thinking?

How do you get the number of keys in a JSON object?

I am creating a gallery plug-in in which I need to figure out the number of elements in a plain javascript object. The following is how I would like to be able to create the gallery.
$.Gallery.create($('#galContainer'), {
'img1.png': 'http://linktosomewhere/',
'img2.png': 'http://linktosomewhere/',
'img3.png': 'http://linktosomewhere/',
........
}, optionsObj);
This will put the images into the gallery with the corresponding links to some page when clicked. Currently I am using an array for that second parameter without the links and I am getting the length of the images using images.length. However using the notation above would be ideal for me and I need to be able to tell how many keys there are in this object.
I am aware of this post and a few others saying you can not get the number of elements in the object. If this is indeed the case, do you have any suggestions on another way to setup this function call which will be efficient and easy to use?
The code you see in the other question you linked to is really the only way to do it. Here's how you can create a function to do it:
function count(obj) {
var i = 0;
for (var x in obj)
if (obj.hasOwnProperty(x))
i++;
return i;
}
Can't you use an array of objects instead?
$.Gallery.create($('#galContainer'), [
{src:'img1.png', href:'http://linktosomewhere/'},
{src:'img2.png', href:'http://linktosomewhere/'},
{src:'img3.png', href:'http://linktosomewhere/'},
........
], optionsObj);
You should just add a .src and .href in your code to read it.
The way you designed your dataset as a simple hash is not very flexible for additional attributes(size, categories, selected, etc...)
Underscore.js has a method that will tell you how large the object is _.size(obj);
Object.prototype.count = function()
{
var c = 0;var i;
for(i in this){if (this.hasOwnProperty(i)){c++;}};
return c;
}
Personally I would build your own prototype for Object, you can use MyObject.length but I think its not fully supported by IE.
test reveal that the length variable is unavailable in Objects.
Testcase:
MyObject = {
a : '0',
b : '1',
c : '2'
}
if(MyObject.count() > 5)
{
$.Gellery.Error('Images','Only 5 images allowed'); //...
}
http://jsfiddle.net/b9Nwv/

Categories