0

I found half of the answer to my problem in the accepted answer on this post. How do I filter an array with AngularJS and use a property of the filtered object as the ng-model attribute?

I wondered if it was possible to filter by another field that would create an array of those objects, then use values from two different objects in that array.

something like this... (the td with ng-show="data.Options.HasMap")

<tbody>
            <tr ng-repeat="row in data.Rows">
                <td ng-repeat="col in row.Columns" ng-show="{{col.Visible}}">
                    {{ col.Value }}
                </td>
                <td ng-show="data.Options.HasMap" ng-repeat="hidden in row.Columns | filter:{Visible:false} track by $index">
                    {{hidden.Value | filter:{HeaderText:'Latitude'}}} , {{hidden.Value | filter:{HeaderText:'Longitude'}}}
                </td>
                <td ng-show="data.Options.HasSuppression">

                </td>
                <td ng-show="data.Options.HasAction">

                </td>
            </tr>
        </tbody>

my Json file has an array of columns like...

"Columns": [{
                 "HeaderText": "R1 - F1",
                 "Value": "data1",
                 "Visible": true
         },...

and i would like to pull the columns out where Visible: false then pick out the Values of two different Objects with specific HeaderTexts.

Sorry if this sounds confusing. any help would be appreciated. I'm very new to Angular and just trying to figure things out!

edit. Just to point out that i can get to one of the column object i need like this.

            <td ng-show="data.Options.HasMap" ng-repeat="hidden in row.Columns | filter:{HeaderText:'Latitude'} track by $index">
                {{ hidden.Value }}
            </td>

But i really need both the Latitude and Longitude column objects to create a url with querystring variables.

i have also tried...

<td ng-show="data.Options.HasMap">
                    {{ row.Columns.Value | filter:{HeaderText:'Latitude'} }} , {{ row.Columns.Value | filter:{HeaderText:'Longitude'} }}
                </td>
Community
  • 1
  • 1
Stuart
  • 1,544
  • 5
  • 29
  • 45

2 Answers2

0

This line will take the value of hidden.Value (which in your example above is "R1 - F1") and apply a filter { HeaderText: 'Latitude'} to it:

{{hidden.Value | filter:{HeaderText:'Latitude'}}} , {{hidden.Value | filter:{HeaderText:'Longitude'}}}

You're attempting to filter a string using a filter meant for an array of objects; this will simply return an empty array and is surely not what you want. It's not clear from your example where 'Longitude' and 'Latitude' properties are defined. Perhaps you wanted to filter the list of columns again? Something like:

I'm not entirely certain what you're trying to do, please explain where the Latitude/Longitude properties are defined.

Another thing to take a look at is custom filters, these may help as well. Take a look at Using filter to create array, then using that array to filter ng-options

EDIT

To get the two columns with HeaderText = "Latitude", and HeaderText = "Longitude", you can do:

<span ng-repeat="col in row.Columns | filter:{HeaderText: "Latitude"}>

If that doesn't suit your needs, look at custom filters. Here's an example that would filter by header text matching any values you pass in:

app.filter('filterByHeaderText', function() {
    return function(input, headerText) {
      // Input is the array to be filtered, 
      input = input || [];
      headerText = headerText || [];

      var output = [];
      for (var i = 0; i < input.length; i++) {
        for (var j = 0; j < headerText.length; j++) {
          // If input matches any of the headerText, then add it to the list
          if (input[i].headerText.indexOf(headerText[j].trim()) >= 0) {
            output.push(input[i]);
            break;
          }
        }
      }

      return output;
    };
  })

This filter can then be used like so:

<span ng-repeat="item in row.Columns | filterByHeaderText: ['Latitude', 'Longitude']">
Community
  • 1
  • 1
mofojed
  • 1,342
  • 9
  • 11
  • sorry i should have mentioned that the longitude and latitude properties are actually objects within the columns. So i want to pull two Column Objects, one with a HeaderText property of "Latitude" and one with a HeaderText of "Longitude". - Is this even possible? – Stuart Jul 27 '15 at 12:44
0

Sorry this is my first answer here. I made custom filter for filtering array like this. Let's say we have array of JSON objects like this:

var myArray=[{prop1:"val1", prop2:"val2", ...}, ...]

The search parameter is defined in property name : property value pairs which should be structured like this:

var examplePairs={
      prop1:"val1",
      prop2:["val2", "val3"],
      prop4:{eqStart:true, eqEnd:false, iStart:123, iEnd: 321}
      };

This example searches array for all matches where property prop1 have value val1 and property prop2 have value val2 or val3 and property prop3 is from interval [123,321>

Note: For interval search, data inside objects in array must be a number(it shouldn't be defined without quotes).

There are explanations in comments. For your specific case call filter like this:

 {{ pairs={HeaderText:['Latitude', 'Longitude'], Visible:true} }}
 <span ng-repeat="col in row.Columns | jsonArrayMultiFilter : pairs >

Or call filter from controller like this:

var pairs={HeaderText:['Latitude', 'Longitude'], Visible:true}
 $scope.row.Columns=$filter('jsonArrayMultiFilter')($scope.row.Columns, pairs);

Custom filter code:

.filter('jsonArrayMultiFilter',  function() {
return function(x, pairs) {
  //filters 
  //pairs = property:value pairs 
  //in case same properties can have multiple value pairs should be defined as followed
  // {property:[value1, value2]}
  //if value of property fits inside interval it should be defined as followed
  // {property:{eqStart:true, eqEnd:false, iStart:"start of interval", iEnd:"end of interval"}}
  //  if value in data is string it searches if string contains searched value 
  var keys=Object.keys(pairs);
  //console.log(keys);
  var newData=[];
  var counter, tempCount, expression;
  for (var i=0;i<x.length;i++){
    //iterate data then apply multiple filters
    //set counter value 0 for each itteration trough data
    //if all pairs satisfies conditions counter should equal (keys.length - 1)
    //for effitiency when condition is not satisfied loop should be broken on first fail
    counter=0;
    for (var j=0; j < keys.length; j++ ){
      //iterrate through pairs
      if (pairs[keys[j]].constructor === Array){
        //if property has multiple values itterate trough values
        tempCount=counter;
        for (var k=0; k < pairs[keys[j]].length; k++){
          //create regexp to perform case insensitive search
          var rExp = new RegExp(pairs[keys[j]][k], "i");
          //if value is a string expression searches the string if it is number finds exact match
          expression=(typeof x[i][keys[j]] == 'string' || x[i][keys[j]] instanceof String)?x[i][keys[j]].search(rExp)>-1:x[i][keys[j]]==pairs[keys[j]][k];
          if (expression){
            counter++;
          }
        }
        if (tempCount==counter){
          //break itteration because one condition isn't satisfied for data x[i]
          break;
        }
      }else{
        //if not array but is object and property['iStart'] is not null and not undefined check if value is from interval
        if( typeof pairs[keys[j]]['iStart'] !== 'undefined' && pairs[keys[j]]['iStart'] !== null ){
          // if value is from interval
          var leftLimit=pairs[keys[j]]['eqStart']?x[i][keys[j]] >= pairs[keys[j]]['iStart']:x[i][keys[j]] > pairs[keys[j]]['iStart'];
          var rightLimit=pairs[keys[j]]['eqEnd']?x[i][keys[j]] <= pairs[keys[j]]['iEnd']:x[i][keys[j]] < pairs[keys[j]]['iEnd'];
          if (leftLimit &&  rightLimit){
            counter++;
          }
          else{
            //break itteration because one condition isn't satisfied for data x[i]
            break;
          }
        }else{
          //create regexp to perform case insensitive search
          var rExp = new RegExp(pairs[keys[j]], "i");
          //if value is a string expression searches the string if it is number finds exact match
          expression=(typeof x[i][keys[j]] == 'string' || x[i][keys[j]] instanceof String)?x[i][keys[j]].search(rExp)>-1:x[i][keys[j]]==pairs[keys[j]];
          //if property has one value make comparsion
          if (x[i][keys[j]]==pairs[keys[j]]){
            counter++;
          }  
          else {
            //break itteration because condition isn't satisfied for data x[i]
            break;
          }
        }
      }
      //if all conditions are satisfied
      if (counter >= keys.length){
        newData.push(x[i]);
      }
    }
  }
  return newData;
};
})