36

I'm transitioning from relying on jQuery to building apps in AngularJS. It's recommended in a number of places to not mix jQuery and Angular code.

One thing I miss though is the jQuery $.map function for arrays. I know this could be re-written using the native Javascript map function, but this is not implemented in all browsers (notably, IE < v9).

So, is there an Angular equivalent, or should I got back to writing for (var x = 0; x < foo; x += 1) {...} so I can stop including jQuery?

UPDATE Sometimes knowing what to search for is all you need. Bergie says 'look for polyfills'. Here's a reference guide (from the Modernizr crew) for a bunch of resources for making modern code work on older browsers: HTML5 Cross Browser Polyfills

Community
  • 1
  • 1
Ben Jacobs
  • 2,526
  • 4
  • 24
  • 34
  • 1
    You could just include a ES5 polyfill, they are simple and exact for those array iterating functions. – Bergi Mar 14 '13 at 14:12
  • 5
    Angular is not meant to be a JS library. It's a framework for building single-page apps. Although it does have a handfull of utility functions (see [angular.forEach](http://docs.angularjs.org/api/angular.forEach)) it does not try to tell you how to handle low-level JS operations. That's what Lo-Dash/Underscore and friends are for. – Stewie Mar 14 '13 at 14:22
  • In addition to what @Stewie mentioned, after a while Angular actually went and dumped a bunch of jquery in and called it JQLite - so you're getting a lot of jquery when you use Angular whether you like it or not. May as well use it. Although there is still a lot of waste in things like Angular's forEach that would be better off leveraging jquery if present. http://docs.angularjs.org/api/angular.element – Chris Moschini Mar 23 '13 at 06:16
  • 1
    The kind of jquery that they warn against mixing with angular is the kind that fiddles with the dom directly, not the utility stuff that maps a function to a javascript array. – flup Dec 07 '14 at 21:27

2 Answers2

26

Check here: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/map

Mozilla has supplied an Array.map polyfill for unsupported browsers

if (!Array.prototype.map) {
  Array.prototype.map = function(callback, thisArg) {

    var T, A, k;

    if (this == null) {
      throw new TypeError(" this is null or not defined");
    }

    // 1. Let O be the result of calling ToObject passing the |this| value as the argument.
    var O = Object(this);

    // 2. Let lenValue be the result of calling the Get internal method of O with the argument "length".
    // 3. Let len be ToUint32(lenValue).
    var len = O.length >>> 0;

    // 4. If IsCallable(callback) is false, throw a TypeError exception.
    // See: http://es5.github.com/#x9.11
    if (typeof callback !== "function") {
      throw new TypeError(callback + " is not a function");
    }

    // 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
    if (thisArg) {
      T = thisArg;
    }

    // 6. Let A be a new array created as if by the expression new Array(len) where Array is
    // the standard built-in constructor with that name and len is the value of len.
    A = new Array(len);

    // 7. Let k be 0
    k = 0;

    // 8. Repeat, while k < len
    while(k < len) {

      var kValue, mappedValue;

      // a. Let Pk be ToString(k).
      //   This is implicit for LHS operands of the in operator
      // b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk.
      //   This step can be combined with c
      // c. If kPresent is true, then
      if (k in O) {

        // i. Let kValue be the result of calling the Get internal method of O with argument Pk.
        kValue = O[ k ];

        // ii. Let mappedValue be the result of calling the Call internal method of callback
        // with T as the this value and argument list containing kValue, k, and O.
        mappedValue = callback.call(T, kValue, k, O);

        // iii. Call the DefineOwnProperty internal method of A with arguments
        // Pk, Property Descriptor {Value: mappedValue, : true, Enumerable: true, Configurable: true},
        // and false.

        // In browsers that support Object.defineProperty, use the following:
        // Object.defineProperty(A, Pk, { value: mappedValue, writable: true, enumerable: true, configurable: true });

        // For best browser support, use the following:
        A[ k ] = mappedValue;
      }
      // d. Increase k by 1.
      k++;
    }

    // 9. return A
    return A;
  };      
}
Rob M.
  • 35,491
  • 6
  • 51
  • 50
13

No, there is no equivalent in Angular. And as you discovered, no you don't need to fall back to writing imperative code.

Instead, just use the map function that is built directly into JavaScript. If you need to support IE8, insert the polyfill at the beginning of your scripts.

Edward Brey
  • 40,302
  • 20
  • 199
  • 253