Checking array object existence - arrays

So, I am trying to check the existence of recently pushed array object.
I am developing the web application using angularJS.
I have an array which is defined as
vm.data.detail
So I have a form that let user to CRUD a module. The module is about product stock take. There is a button that will run addProduct() function in my angular controller.
addProduct function:
function addProduct() {
//to check whether the array is empty.
if (vm.data.detail.length == 0) {
vm.data.detail.push({
product: vm.data.product_id.selected,
current_qty: vm.data.product_id.selected.qty,
new_qty: Number(vm.data.product_id.selected.qty) - Number(1),
difference: Number(vm.data.product_id.selected.qty) - (Number(vm.data.product_id.selected.qty) - Number(1)),
remarks: ''
});
console.log("Product just been added");
}
//if the array is not empty
else {
for (var i = 0; i < vm.data.detail.length; i++) {
//to check whether the selected product is already inside the array
if (vm.data.product_id.selected.name == vm.data.detail[i].product.name) {
console.log("same product selected");
//data
}
//if there is no selected product inside the array, then add it
else {
console.log("different product has just been selected");
vm.data.detail.push({
product: vm.data.product_id.selected,
current_qty: vm.data.product_id.selected.qty,
new_qty: 0,
difference: 0,
remarks: ''
});
}
}
}
}
Above code works well when the array just consists of one product. The problem occurs when I am trying to add another product B into the product. Here is the condition :
Product A is already inside the array.
Product B is selected, and then added into the array. Now the array consists of 2 products.
When I am testing to add a new product B, I don't know why the array is still pushed with a new Product B. So now, the array consists of 3 Products (1 Product A, and 2 Product B).
What I wanted is, when I am trying to add the second product B, the array won't be pushed by new product B.
What am I missing here? Have been dealing with it for hours and can't figure out what I have to add for the "validation".
Please note that, the object the array pushing is already correct. I am just don't know how to put the if else. Looks like the logic inside is still lacking of something, but I couldn't figure out what is missing
Thank you so much for the help given.

You're commiting a simple mistake, you are doing the check of else inside the array, you must move it to outside.
Tips:
You can use Array.prototype.find() method to check if the element exists in array, which is much better than perform a traditional for-loop.
As you may have noticed in documentation, the find method have no compatibility with IE and Opera browsers, so if you need this compatibility, you can use Array.prototype.filter().
Below is the code, with both versions (with find and filter) and also with the necessary modifications:
function addProduct() {
//to check whether the array is empty.
if (!vm.data.detail.length) { // you can simply use (!length) instead of comparing with 0
vm.data.detail.push({
product: vm.data.product_id.selected,
current_qty: vm.data.product_id.selected.qty,
new_qty: Number(vm.data.product_id.selected.qty) - Number(1),
difference: Number(vm.data.product_id.selected.qty) - (Number(vm.data.product_id.selected.qty) - Number(1)),
remarks: ''
});
console.log("Product just been added");
}
//if the array is not empty
else {
// if there's no obj with the same name inside the array, it returns undefined, otherwise it returns the object.
var obj = vm.data.detail.find(function(value) {
return value.product.name == vm.data.product_id.selected.name;
});
/* Using FILTER:
var obj = vm.data.detail.filter(function(value) {
return value.product.name == vm.data.product_id.selected.name;
})[0];
*/
// Now you can test, if the object exists
if (obj) {
console.log("same product selected");
}
//if there is no selected product inside the array, then add it
else {
console.log("different product has just been selected");
vm.data.detail.push({
product: vm.data.product_id.selected,
current_qty: vm.data.product_id.selected.qty,
new_qty: 0,
difference: 0,
remarks: ''
});
}
}
}
I hope it helps!

It's a basic logic error. You're doing
for each element {
if element is different from given {
add given to array
}
}
What you need to do is
var allElementsDifferentFromGiven = true
for each element {
if element is same as given {
allElementsDifferentFromGiven = false
break
}
}
if (allElementsDifferentFromGiven) {
add given to array
}
But JavaScript arrays have methods to do that:
if (array.every(function(element) {
return true if element is different given
})) {
add given to array
}

I think problem is here :
because there product is property on Detail object and product does not have name property , it is not matching criteria and going to else condition and pushing into name list.
//to check whether the selected product is already inside the array
if(vm.data.product_id.selected.name == vm.data.detail[i].product.name){
it should be
//to check whether the selected product is already inside the array
if(vm.data.product_id.selected.name == vm.data.detail[i].product){
console.log("same product selected");
//data
}

Related

how to add an object to array immediately after set to empty "[ ]" Vue

I need after call a function, set to empty an array and immediately add a new one to there.
This is becouse when an #click event is called i need to call a dialog and populate the content of this with a dynamic component (called them with a slug propertie), so the array should be change accordily to pass the slug propertie to the component.
My code is:
slugs: []
slugConversacion(slug) {
if (this.slugs > 0) {
this.slugs = []
// this.slugs.splice(this.slugs.indexOf(slug), 0);
// this.$delete(this.slugs, this.slugs.indexOf(slug))
}
else {
this.slugs.push(slug);
}
}
<Conversacion
v-for="slug in slugs"
:key="slug.id"
:slug="slug.slug"
></Conversacion>
This not work because when i click the event slugConversacion() set and empty array and only when clicked again, populate. I think that is for the if/else conditional.
What would be the right approach ? Thanks!
Just do this:
if (this.slugs.length > 0) {
this.slugs = [];
}
this.slugs.push(slug);
If you have trouble with setting array to empty with assigning [] to array and loosing reactivity, then you can try next thing.
This works for me as the last resort:
var i = slugs.length;
while(i --){
slugs.splice(i, 1);
}
You should do splice in revers mode because of index confusion: every time will be remained array element with index 1 if you will go throw the loop via
slugs.forEach((item, index) => {
slugs.splice(index, 1);
});
And after that you can do:
this.slugs.push(slug);

Protractor check if element is present on a LIST using element.all

I need to do an assertion to check if an element is present inside 'elements.all'.
My first idea is to run a for loop and put an expect inside. Not a great idea because it is checking every single items on list. So if I have 30 items, I might end up with 29 fails.
element.all(by.css(element)).then(function(itemList) {
console.log("Total values in dropdown are: " + itemList.length);
for (i = 0; i < itemList.length; i++) {
itemList[i].getText().then(function(text) {
console.log(text);
expect(text).toEqual('whatever-i-need-to-assert');
});
};
});
In order to solve this problem, I nest an IF statement that will 'pre-check' for a string match. Another bad idea because if there is no match, my expect will never run, thus, giving me a false pass:
element.all(by.css(".item a.gc-exercises-link")).then(function(itemList) {
console.log("Total values in dropdown are: " + itemList.length);
for (i = 0; i < itemList.length; i++) {
itemList[i].getText().then(function(text) {
console.log(text);
if (text == 'BOATLIFT-EXERCISE') {
console.log('Match');
expect(text).toEqual('BOATLIFT-EXERCISE');
} else {
console.log('No Match');
};
});
};
});
Clearly, I am in the wrong path here. Can someone give me an idea how to properly expect for a 'Text' when using element.all. I just need to prove that a text is present on the said list.
Thanks!
Here is an example to check that there is a link with the text "Terms" in a page :
browser.get('https://www.google.co.uk/');
expect(element.all(by.css('a')).getText()).toContain('Terms');
Note that for each element, protractor needs to interogate the browser, which could be slow especially if there is a lot of elements.
A quicker solution would be to check that at least one element is present with a XPath including the expected text:
browser.get('https://www.google.co.uk/');
expect(element.all(by.xpath("//a[text()='Terms']")).count()).toBeGreaterThan(0);
If you just want to check it's present (and other list item's won't interfere), you could call .getText() on the array after element.all, before .then and use toContain()
element.all(by.css(".item a.gc-exercises-link")).getText().then(function(itemList) {
expect(itemList).toContain('some text');
};
Or if you know the index:
element.all(by.css(".item a.gc-exercises-link")).getText().then(function(itemList) {
expect(itemList[3]).toEqual('some text');
}
As a side note: you can use .each() instead of creating a for loop https://angular.github.io/protractor/#/api?view=ElementArrayFinder.prototype.each
You can use filter function.
$$("span").filter(function(elem,index){
return elem.getText().then(function(txt){
return txt === 'text to compare';
});
}).then(function(eleList){ // you get the list of elements containing the text here
console.log(eleList.length);
});

Angular - Objects seem bound to eachother but arent

I have an edit page where the user can edit a file in the system, and then save it. When loading the file, I make two objects out of the result, one is bound to the view and the other I wish to keep (in its original state) until "save" is clicked, and then use it to compare vs the view-bound object, to see if any changes have been made.
So, when the page loads, this is being run
$http.get('/api/files/' + $stateParams.id)
.then(function (result) {
vm.fileTemp = result.data;
vm.fileTempCopy = result.data;
The fileTempCopy is not being touched or referenced by anything in the view or elsewhere in the controller, except in the save-method, where i check if they are alike or not. But somehow, both of them are updated when i make changes to the input fields (as if they were both used as ng-model for the inputs).
if(vm.fileTemp === vm.fileTempCopy)//in save-function
is always true, and their fields are exactly the same.
Why does this happen and how can I solve it?
Using the assignment operator, you are actually just referencing the original array. Arrays are reference types. That means, that they don't actually store values, they only store references to those values. What you where doing is copying a reference to a memory location, meaning that any changes to the memory at that location (including removing elements) will be reflected in both arrays.
So you will want to do this instead:
vm.fileTemp = angular.copy(result.data);
vm.fileTempCopy = angular.copy(result.data);
here is a very basic approach to checking an object's "value equality".
function isEquivalent(a, b) {
// Create arrays of property names
var aProps = Object.getOwnPropertyNames(a);
var bProps = Object.getOwnPropertyNames(b);
// If number of properties is different,
// objects are not equivalent
if (aProps.length != bProps.length) {
return false;
}
for (var i = 0; i < aProps.length; i++) {
var propName = aProps[i];
// If values of same property are not equal,
// objects are not equivalent
if (a[propName] !== b[propName]) {
return false;
}
}
// If we made it this far, objects
// are considered equivalent
return true;
}
//After your update Outputs: false
console.log(isEquivalent(vm.fileTemp, vm.fileTempCopy));

AS3 "for each" array issue

I am trying to create a system that displays the name of the button that you press.
The button names are put into an array, however it only recognized the last item entered into the array.
Help would be greatly appreciated.
var items:Array = [a, b, c]; //The name of each button
for each(var index in items)
{
index.addEventListener(MouseEvent.CLICK, mouseClickHandler);
}
function mouseClickHandler(event:MouseEvent):void
{
trace(index.name); //Should display the name of any of the buttons clicked.
}
You should trace the currentTarget name:
var items:Array = [a, b, c]; //The name of each button
for each(var index in items) {
index.addEventListener(MouseEvent.CLICK, mouseClickHandler);
}
function mouseClickHandler(event:MouseEvent):void {
trace(event.currentTarget.name); //Should display the name of any of the buttons clicked.
}
There's only one index variable created here - and mouseClickHandler function, obviously, works with its current value only. If you need to refer to specific values (given at each loop step), you need to localize them in one way or another:
function generateClickHandler(index:someType) {
return function(event:MouseEvent):void { trace(index.name); }
}
...
for each(var index in items)
{
index.addEventListener(MouseEvent.CLICK, generateClickHandler(index);
}
I'd suggest checking this thread as well.

How would I remove a "row" in an array depending on the value of an element?

Here's what I'm currently doing/trying to do to accomplish my goal. But it is not removing the "row" the way I would like it too.
So, I'm making an object, then pushing it into an array. And the adding to the array part works fine and just as I expect.
var nearProfileInfoObj:Object = new Object();
nearProfileInfoObj.type = "userInfo";
nearProfileInfoObj.dowhat = "add";
nearProfileInfoObj.userid = netConnection.nearID;
nearProfileInfoObj.username = username_input_txt.text;
nearProfileInfoObj.sex = sex_input_txt.selectedItem.toString();
nearProfileInfoObj.age = age_input_txt.selectedItem;
nearProfileInfoObj.location = location_input_txt.text;
nearProfileInfoObj.headline = headline_input_txt.text;
theArray.push(nearProfileInfoObj);
So after that later on I need to be able to remove that object from the array, and it's not working the way I'm expecting. I want to take a variable whoLeft and capture their ID and then look in the array for that particular ID in the userid part of the object and if its there DELETE that whole "row".
I know you can do a filter with an array collection but that doesnt actually delete it. I need to delete it because I may be adding the same value again later on.
whoLeft = theiruserIDVariable;
theArray.filter(userLeaving);
public function userLeaving(element:*, index:int, arr:Array):Boolean
{
if (element.userid == whoLeft)
{
return false;
}
else
{
return true;
}
}
But this doesnt seem to be deleting the whole row like it implies. Does anyone know what i'm doing wrong?
Instead of modifying the original array, the new filtered array is returned by the filter method. So you need to assign the returned array to theArray.
Try this
theArray = theArray.filter(userLeaving);
EDIT This turned out to be slower than for loop:
An alternative to the hand coded loop could be something like this:
theArray.every(searchAndDestroy);
public function searchAndDestroy(element:*, index:int, arr:Array):Boolean
{
if (element.userid == whoLeft)
{
arr.splice(index,1);
return false;
}
return true;
}
As far as I know, every() terminates the first time the test function returns false. So the question is: for a big list, which is faster, the for loop or the loop that every() does with the overhead of the test function call.
EDIT #2 But this was faster than a for loop for a test I ran on an array of a million Points:
for each(var element:Object in theArray)
{
if (element.userid==whoLeft)
{
theArray.splice(theArray.indexOf(element),1);
break;
}
}
I think this is what you're looking for:
for(var i:uint = 0, len:uint = theArray.length; i<len; i++)
{
if(thisArray[i].id == whoLeft.id)
{
thisArray.splice(i, 1);
break;
}
}
However, do you really need it in an Array because you could always use a Dictionary which would mean accessing it by id which would be a lot simpler to remove.

Resources