3

I have ViewModel and one of its properties is an observableArray (receivers). I want to check if an email address already exist to the collection before adding new record to ensure that no duplicate entries will occur. Please help. I tried the approach from here How to conditionally push an item in an observable array? but it's not working. It cannot detect if item to be added with email already on the list. I want that if AddReceiver function is called I will validate the newReceiverData email address. Here's my code.

ViewModel

var ReceiversViewModel = function () {
    var self = this;
    var errorModal = {};

    self.firstname = ko.observable();
    self.lastname = ko.observable();
    self.receivers = ko.observableArray();
    self.newReceiver = {
        receiverfirstname: ko.observable(''),
        receiverlastname: ko.observable(''),
        receiveremailaddress: ko.observable('')
    };
       self.AddReceiver = function () {
        var newReceiverData = ko.toJS(self.newReceiver);
        if (ReceiverValidate() == true) {
        //check if newReceiverData.receiveremailaddress value already exist
            self.receivers.push({
                EmailAddress: newReceiverData.receiveremailaddress,
                FirstName: newReceiverData.receiverfirstname,
                LastName: newReceiverData.receiverlastname
            });
        }
    }; 
};
Community
  • 1
  • 1
Jobert Enamno
  • 4,403
  • 8
  • 41
  • 63

2 Answers2

3

I normally use the "any" function in the lightweight underscore.js library for this sort of thing when I work with knockout.

if (!_.any(self.receivers(), function(receiver) { return receiver.receiveremailaddress() == newReceiver.receiveremailaddress(); })) {
            // push new receiever 
        }

You can make the comparison function as simple or as complex as you want.

Rune Vejen Petersen
  • 3,201
  • 2
  • 30
  • 46
  • I got error "JavaScript runtime error: Unable to get property 'receiveremailaddress' of undefined or null reference" I think because receiver is undefined but self.receivers() has items in it – Jobert Enamno May 30 '13 at 03:49
  • Do all the receivers in your self.receivers() observableArray have this property? The "any" function runs through them all and looks at this property (the current comparison function I wrote expects this property to be there) – Rune Vejen Petersen May 30 '13 at 08:20
1

You could change your self.AddReceiver function to something like this:

self.AddReceiver = function () {
    var newReceiverData = ko.toJS(self.newReceiver);
    if (ReceiverValidate() == true) {

        //get just the email addresses from your receiver collection:
        var emailAddressInReceivers = ko.utils.arrayMap(self.receivers, function (item) {
                item.EmailAddress;
            });

        //only push into array if email address isn't in emailAddressInReceivers
        if (emailAddressInReceivers.indexOf(newReceiverData.receiveremailaddress < 0) {
                self.receivers.push({
                        EmailAddress: newReceiverData.receiveremailaddress,
                        FirstName: newReceiverData.receiverfirstname,
                        LastName: newReceiverData.receiverlastname
                    });
            }
        }
    };
};

This basically flattens your list of receivers to return just the emailAddress, then only adds a new receiver to the array if the email address you're pushing isn't in that list

Alex
  • 37,502
  • 51
  • 204
  • 332
  • Thanks for your help buddy but I got problem. emailAddressInReceivers returns [] even though new items have been pushed to self.receivers. Since emailAddressInReceivers is [] new item with duplicate email is still adding to the collection. – Jobert Enamno May 29 '13 at 09:56
  • Yes, it's an array of string (email addresses) that are currently in self.receivers. The next line basically says if emailAddressInReceivers DOES NOT contain newReceiverData.receiveremailaddress then add it – Alex May 29 '13 at 12:13
  • 1
    Please note that indexOf() is not supported in IE8 or lower. (see http://stackoverflow.com/a/3629211/1016885) – Rune Vejen Petersen May 29 '13 at 13:00
  • Could use ko.utils.arrayIndexOf instead, which is supported in IE8 – Alex May 29 '13 at 13:51
  • These are all great examples. Please consider using arrayFirst. See here for documentation: http://www.knockmeout.net/2011/04/utility-functions-in-knockoutjs.html – Matthew James Davis May 29 '13 at 17:51