简体   繁体   English

AngularJS-如何按对象的属性/属性过滤-forEach不是函数

[英]AngularJS- How to filter by property/ attribute of an object- forEach is not a function

I have an AngularJS application, and on one of the pages, there are a number of widgets displayed. 我有一个AngularJS应用程序,并且在其中一个页面上,显示了许多小部件。 One of the widgets displays a table containing information about a system that is being monitored by the application. 小部件之一显示一个表,其中包含有关应用程序正在监视的系统的信息。 This table currently contain two columns: a 'Type' column, displaying the type of information shown in that row; 该表当前包含两列:“类型”列,显示该行中显示的信息类型; and a 'Data' column, displaying the value of the variable that holds that information. 和“数据”列,显示保存该信息的变量的值。

It is possible to customise the information displayed on the widget using a dialog that is opened when the 'Settings' button is clicked on the widget toolbar. 可以使用单击小部件工具栏上的“设置”按钮时打开的对话框来自定义小部件上显示的信息。 There are 'Columns' and 'Rows' text input fields on that dialog which are used to set the columns headings and rows to be displayed in the table. 该对话框上有“列”和“行”文本输入字段,用于设置要在表中显示的列标题和行。 Currently, when the user starts typing into the 'Rows' text input field, a drop down list is displayed showing the user the variables that are available to be displayed in the table, and that match what the user has typed (ie as they continue to type, the list of options available will get more specific). 当前,当用户开始在“行”文本输入字段中键入内容时,将显示一个下拉列表,向用户显示可在表中显示的变量,这些变量与用户键入的内容匹配(即继续输入)进行键入,可用选项列表将更加具体)。

The function used to display this drop down to the user while they type in the text input field is: 在用户输入文本输入字段时向用户显示此下拉菜单的功能是:

$scope.autocompleteVarsFilter = function(query) {
    if(!query && lastVarQryKw) {
        query = lastVarQryKw;
    }
    var result = Object.keys(fxVar.getVars()).filter(function(name) {
        return name.indexOf(query.toLowerCase()) !== -1;
    });

    if(result.length > 0) {
        lastVarQryKw = query;
    }
    return result;
};

I am currently trying to add a third column to that table, to display a link to a given page that the user will choose. 我目前正在尝试在该表中添加第三列,以显示指向用户将选择的给定页面的链接。 I decided that a 'link' would be denoted by a string starting with the character : (ie if the user types in :index , that would be a link to the home page of the site). 我决定以一个以字符:开头的字符串来表示“链接”(即,如果用户输入:index ,那将是指向该网站首页的链接)。

As soon as the user types : , the full list of available pages should be displayed in a 'drop-down', and as the user continues to type, this list should be filtered based on what they are typing (as it is with variable names) 用户键入: ,可用页面的完整列表应在“下拉列表”中显示,并且当用户继续键入时,应根据他们键入的内容(包括变量)过滤此列表。名)

I have updated my function as follows: 我已经更新了我的功能,如下所示:

$scope.autocompleteVarsFilter = function(query) {
    if(query.startWith(":") {
        var buttonsQuery = query.substring(1);
        if(!buttonsQuery && lastVarQryKw) {
            buttonsQuery = lastVarQryKw;
        }

        var userPages = pagesPresets; //This is getting the full list of available pages from a service called 'pagesPresets'
        console.log("Value of userPages: ", userPages);

        var page;
        for(page in userPages) {
            console.log("for loop started");
            if(page.key.startWith(buttonsQuery)) {
                console.log("Matching page found: ", page);
            }
        }

        if(result.length > 0) {
            lastVarQryKw = query;
        }
        return result;

    } else {
        if(!query && lastVarQryKw) {
            query = lastVarQryKw;
        }
        var result = Object.keys(fxVar.getVars()).filter(function(name) {
            return name.indexOf(query.toLowerCase()) !== -1;
        });

        if(result.length > 0) {
            lastVarQryKw = query;
        }

        return result;
    }
};

The else clause of the if statement is doing what the function was originally doing (ie displaying the available variables), and currently still works as intended. if语句的else子句正在执行该函数最初的工作(即显示可用变量),并且当前仍按预期工作。 However, when testing this feature, if I now type : followed by any string into the text input field, the if clause runs, but the available pages are not displayed in a drop down, and I see the following output displayed in the console by my console.log() statements: 但是,在测试此功能时,如果我现在在文本输入字段中键入:然后输入任何字符串, if运行if子句,但是可用页面不会显示在下拉列表中,并且我看到以下输出显示在控制台中我的console.log()语句:

Value of userPages: userPages的值:

0: {_id: "...", _rev: 1, _url: "...", key: "pages/auth", {...}, ...} 0:{_ id:“ ...”,_ rev:1,_url:“ ...”,键:“ pages / auth”,{...},...}

1: {_id: "...", _rev: 13, _url: "...", key: "pages/userpage2", value: {...}, ...} 1:{_ id:“ ...”,_ rev:13,_url:“ ...”,键:“ pages / userpage2”,值:{...},...}

2: {_id: "...", _rev:13, _url: "...", key: "pages/", value: "/pages/userpage1", ...} 2:{_ id:“ ...”,_ rev:13,_url:“ ...”,键:“ pages /”,值:“ / pages / userpage1”,...}

for loop started for循环开始

TypeError: Cannot read property 'startsWith' of undefined TypeError:无法读取未定义的属性“ startsWith”

The issue seems to be that I can't reference the key attribute/ property of the userpage objects to match their value to the value that the user is typing into the text box. 问题似乎是我无法引用userpage对象的key属性/属性来使其值与用户在文本框中键入的值相匹配。

Given that I can see that the page objects I'm using have an attribute key that holds the value I want to filter by, how do I actually get hold of this key attribute to use it? 鉴于我可以看到正在使用的page对象具有保存要过滤的值的属性key ,实际上我该如何获取此key属性以使用它?

I tried changing that for loop to: 我尝试将其for循环更改for

var page;
var key;
for(page in userPages) {
    console.log("for loop started");
    key = page.getAttribute("key");
    if(key.startsWith(buttonsQuery)) {
        console.log("Matching page found: ", page);
    }
}

but this just gives the output: 但这只是输出:

for loop started for循环开始

TypeError: page.getAttribute is not a function TypeError:page.getAttribute不是函数

Anyone have any suggestions? 有人有什么建议吗?

Edit 编辑

I tried doing what @Alex K suggested in their answer, and updated the for loop in my function to: 我尝试做@Alex K在他们的答案中建议的操作,并将函数中的for循环更新for

var page;
var pageKey;
var key;
var result;

console.log("Iterating using foreach");
for(page in userPages) {
    page = userPages[page];
    if(page.key.startsWith(buttonsQuery)) {
        console.log("Matching page found: ", page.key);
        pageKey = page.key;
        result = pageKey;
    }
};

I also tried updating it to: 我也尝试将其更新为:

userPages.forEach(function(page) {
    page = userPages[page];
    if(page.key.startsWith(buttonsQuery)) {
        console.log("Matching page found: ", page.key);
        pageKey = page.key;
        result = pageKey;
    }
});

and: 和:

userPages.forEach(function(page) {
    page = userPages[page];
    if(page.key.startsWith(buttonsQuery)) {
        console.log("Matching page found: ", page.key);
        pageKey = page.key;
        result = pageKey;
    }
});

But these all gave the same output in the console, which was: 但是这些都在控制台中提供了相同的输出,即:

Iterating using foreach 使用foreach进行迭代

ctrl.js:483 Matching page found: pages/userpage2 ctrl.js:483找到匹配的页面:pages / userpage2

ctrl.js:483 Matching page found: pages/userpage1 ctrl.js:483找到匹配的页面:pages / userpage1

ctrl.js:483 Matching page found: pages/ ctrl.js:483找到匹配的页面:pages /

ctrl.js:483 Matching page found: pages/pagetitle ctrl.js:483找到匹配的页面:页面/页面标题

ctrl.js:483 Matching page found: pages/auth ctrl.js:483找到匹配的页面:pages / auth

angular.js:10160 TypeError: a.forEach is not a function
at Object.b.makeObjectArray (ng-tags-input.min.js:1)
at ng-tags-input.min.js:1
at wrappedCallback (angular.js:11735)
at wrappedCallback (angular.js:11735)
at angular.js:11821
at Scope.$eval (angular.js:12864)
at Scope.$digest (angular.js:12676)
at Scope.$apply (angular.js:12968)
at angular.js:14494
at completeOutstandingRequest (angular.js:4413)

So clearly the line from inside the if statement was being run, because I was getting all of those print statements in the console, and yet for some reason, it thinks that forEach is not a function... 显然,正在运行if语句内部的行,因为我正在控制台中获取所有这些print语句,但是由于某种原因,它认为forEach不是函数...

Anyone have any suggestions for how to fix this? 有人对如何解决此问题有任何建议吗?

A for...in loop iterates over the enumerable property names of an object . for...in循环遍历对象的可枚举属性名称 You then need to access the object using that property name to get the value. 然后,您需要使用该属性名称访问对象以获取值。 Here's an example: 这是一个例子:

 console.log('Using for...in on an object:'); var myObj = { 'prop1': 'Hello world!', 'prop2': 12345, 'some crazy property': null }; for (var propName in myObj) { console.log('propName is ' + propName); //Now we can lookup the value using that property name. var propValue = myObj[propName]; console.log('myObj[' + propName + '] is ' + propValue); } 

In contrast, a forEach loop iterates directly over the values of an array . 相反, forEach循环直接在array上进行迭代。 Your callback function is provided the value directly, so you don't need to access the array to retrieve it. 您的回调函数将直接获得该值,因此您无需访问该数组即可检索它。 Example: 例:

 console.log('Using forEach on an array:'); var myArray = [ {key: 'this is object 1!'}, {key: 'this is object 2!'} ]; myArray.forEach(function (obj) { console.log('in ForEach loop...'); console.log('obj is ' + JSON.stringify(obj)); //We can directly access the object's properties as needed console.log('obj.key is ' + obj.key); }); 

So, here's how you can update your code using for...in or using forEach : 因此,这是使用for...in或使用forEach更新代码的方法:

 var buttonsQuery = 'pages/userpage2'; var userPages = [{ _id: "...", _rev: 1, _url: "...", key: "pages/auth" }, { _id: "...", _rev: 13, _url: "...", key: "pages/userpage2" }, { _id: "...", _rev: 13, _url: "...", key: "pages/", value: "/pages/userpage1" } ] console.log('Iterating using for...in'); for (var prop in userPages) { console.log('prop is ' + prop); //Access the page object using the property name var page = userPages[prop]; console.log('page is ' + JSON.stringify(page)); if (page.key.startsWith(buttonsQuery)) { console.log("Matching page found: ", page); } } //Better way to iterate if userPages is an array: console.log('iterating using forEach'); userPages.forEach(function(page) { //page is already the object we're interested in. //No need to access the array again. console.log('page is ' + JSON.stringify(page)); //Access the object's properties as needed if (page.key.startsWith(buttonsQuery)) { console.log("Matching page found: ", page); } }); 

You can also use a for...of loop to iterate, but that's not supported in IE. 您也可以使用for...of loop进行迭代,但是IE不支持。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM