使用角度,如何仅在DOM元素的ID与范围变量匹配时才显示它?

时间:2021-12-25 19:38:07

I am relatively new to AngularJS.

我对AngularJS比较陌生。

I have a series of DIVs in a partial view. Each of the DIVs has a unique ID. I want to show / hide these DIVs based on a scope value (that matches one of the unique ID).

我有一些歌剧女主角。每个div都有一个唯一的ID。我想基于一个范围值(匹配唯一ID)来显示/隐藏这些div。

I can successfully write out the scope value in the view using something like {{showdivwithid}}

我可以使用{{{showdivwithid}}在视图中成功地写出范围值

What would be the cleanest way to hide all the sibling divs that dont have an ID of {{showdivwithid}}

隐藏所有没有{{showdivwithid} ID}的兄弟姐妹的最干净的方法是什么?

2 个解决方案

#1


2  

I think you are approaching the problem with a jQuery mindset.

我认为你是用jQuery思维来解决这个问题的。

Easiest solution is to not use the id of each div and use ngIf.

最简单的解决方案是不使用每个div的id并使用ngIf。

<div ng-if="showdivwithid==='firstDiv'">content here</div>
<div ng-if="showdivwithid==='secondDiv'">content here</div>
<div ng-if="showdivwithid==='thirdDiv'">content here</div>

If you don't mind the other elements to appear in the DOM, you can replace ng-if with ng-show.

如果您不介意其他元素出现在DOM中,则可以用ng-show替换ng。

Alternatively use a little directive like this:

app.directive("keepIfId", function(){
    return {
        restrict: 'A',
        transclude: true,
        scope: {},
        template: '<div ng-transclude></div>',
        link: function (scope, element, atts) {
            if(atts.id != atts.keepIfId){
                element.remove();
            }
        }
    };
});

HTML

HTML

<div id="el1" keep-if-id="{{showdivwithid}}">content here</div>
<div id="el2" keep-if-id="{{showdivwithid}}">content here</div>
<div id="el3" keep-if-id="{{showdivwithid}}">content here</div>

#2


1  

First, I want to echo @david004's answer, this is almost certainly not the correct way to solve an AngularJS problem. You can think of it this way: you are trying to make decisions on what to show based on something in the view (the id of an element), rather than the model, as Angular encourages as an MVC framework.

首先,我想重复@david004的答案,这几乎肯定不是解决AngularJS问题的正确方法。您可以这样想:您正在尝试根据视图中的某个东西(一个元素的id)来决定要显示什么,而不是像MVC框架那样作为角度鼓励的模型。

However, if you disagree and believe you have a legitimate use case for this functionality, then there is a way to do this that will work even if you change the id that you wish to view. The limitation with @david004's approach is that unless showdivwithid is set by the time the directive's link function runs, it won't work. And if the property on the scope changes later, the DOM will not update at all correctly.

但是,如果您不同意并且相信您有一个合法的用例来实现这个功能,那么有一种方法可以做到这一点,即使您更改了您希望查看的id。@david004方法的局限性是,除非在指令的链接函数运行时设置showdivwithid,否则它不会工作。如果在以后范围内的属性更改,DOM将不会正确地更新。

So here is a similar but different directive approach that will give you conditional hiding of an element based on its id, and will update if the keep-if-id attribute value changes:

这里有一种类似但不同的指令方法,它将根据元素的id对其进行有条件隐藏,如果keep-if-id属性值发生变化,它将进行更新:

app.directive("keepIfId", function(){
    return {
        restrict: 'A',
        transclude: true,
        scope: {
          keepIfId: '@'
        },
        template: '<div ng-transclude ng-if="idMatches"></div>',
        link: function (scope, element, atts) {
            scope.idMatches = false;
            scope.$watch('keepIfId', function (id) {
              scope.idMatches = atts.id === id;
            });
        }
    };
});

Here is the Plunkr to see it in action.

这是柱塞。

Update: Why your directives aren't working

更新:为什么你的指令不能工作

As mentioned in the comments on @david004's answer, you are definitely doing things in the wrong way (for AngularJS) by trying to create your article markup in blog.js using jQuery. You should instead be querying for the XML data in BlogController and populating a property on the scope with the results (in JSON/JS format) as an array. Then you use ng-repeat in your markup to repeat the markup for each item in the array.

正如@david004的回答中提到的,您试图在blog中创建文章标记,显然是在用错误的方式(对于AngularJS)做事情。js使用jQuery。您应该在BlogController中查询XML数据,并将结果(JSON/JS格式)作为数组填充到范围上的属性。然后在标记中使用ng-repeat来重复数组中的每个条目的标记。

However, if you must just "get it working", and with full knowledge that you are doing a hacky thing, and that the people who have to maintain your code may hate you for it, then know the following: AngularJS directives do not work until the markup is compiled (using the $compile service).

但是,如果你必须“得到工作”,和完整的知识,你是做一个出租汽车司机的事情,而且必须维护你代码的人可能恨你,然后知道以下:AngularJS指令不工作直到标记编译(使用$编译服务)。

Compilation happens automatically for you if you use AngularJS the expected, correct way. For example, when using ng-view, after it loads the HTML for the view, it compiles it.

如果您使用AngularJS的预期,正确的方法,编译就会自动发生。例如,在使用ng-view时,在加载视图的HTML之后,它会编译它。

But since you are going "behind Angular's back" and adding DOM without telling it, it has no idea it needs to compile your new markup.

但是,由于您正在“在棱角的背后”添加DOM而没有告知它,因此它不知道需要编译新的标记。

However, you can tell it to do so in your jQuery code (again, if you must).

但是,您可以在jQuery代码中告诉它这样做(如果您必须这样做的话)。

First, get a reference to the $compile service from the AngularJS dependency injector, $injector:

首先,从AngularJS依赖注入器获得$compile服务的引用,$injector:

var $compile = angular.element(document.body).injector().get('$compile');

Next, get the correct scope for the place in the DOM where you are adding these nodes:

接下来,获取要添加这些节点的DOM中的位置的正确范围:

var scope = angular.element('.blog-main').scope();

Finally, call $compile for each item, passing in the item markup and the scope:

最后,为每个项目调用$compile,传入项目标记和范围:

var compiledNode = $compile(itm)(scope);

This gives you back a compiled node that you should be able to insert into the DOM correctly:

这将返回一个编译后的节点,您应该能够正确地插入到DOM中:

$('.blog-main').append(compiledNode);

Note: I am not 100% sure you can compile before inserting into the DOM like this.

注意:在像这样插入DOM之前,我不能100%确定您是否可以进行编译。

So your final $.each() in blog.js should be something like:

所以你最后的$.each()在博客中。js应该是:

var $compile = angular.element(document.body).injector().get('$compile'),
    scope = angular.element('.blog-main').scope();
$.each(items, function(idx, itm) {
      var compiledNode = $compile(itm)(scope);
      $('.blog-main').append(compiledNode); 
      compiledNode.readmore();
});

#1


2  

I think you are approaching the problem with a jQuery mindset.

我认为你是用jQuery思维来解决这个问题的。

Easiest solution is to not use the id of each div and use ngIf.

最简单的解决方案是不使用每个div的id并使用ngIf。

<div ng-if="showdivwithid==='firstDiv'">content here</div>
<div ng-if="showdivwithid==='secondDiv'">content here</div>
<div ng-if="showdivwithid==='thirdDiv'">content here</div>

If you don't mind the other elements to appear in the DOM, you can replace ng-if with ng-show.

如果您不介意其他元素出现在DOM中,则可以用ng-show替换ng。

Alternatively use a little directive like this:

app.directive("keepIfId", function(){
    return {
        restrict: 'A',
        transclude: true,
        scope: {},
        template: '<div ng-transclude></div>',
        link: function (scope, element, atts) {
            if(atts.id != atts.keepIfId){
                element.remove();
            }
        }
    };
});

HTML

HTML

<div id="el1" keep-if-id="{{showdivwithid}}">content here</div>
<div id="el2" keep-if-id="{{showdivwithid}}">content here</div>
<div id="el3" keep-if-id="{{showdivwithid}}">content here</div>

#2


1  

First, I want to echo @david004's answer, this is almost certainly not the correct way to solve an AngularJS problem. You can think of it this way: you are trying to make decisions on what to show based on something in the view (the id of an element), rather than the model, as Angular encourages as an MVC framework.

首先,我想重复@david004的答案,这几乎肯定不是解决AngularJS问题的正确方法。您可以这样想:您正在尝试根据视图中的某个东西(一个元素的id)来决定要显示什么,而不是像MVC框架那样作为角度鼓励的模型。

However, if you disagree and believe you have a legitimate use case for this functionality, then there is a way to do this that will work even if you change the id that you wish to view. The limitation with @david004's approach is that unless showdivwithid is set by the time the directive's link function runs, it won't work. And if the property on the scope changes later, the DOM will not update at all correctly.

但是,如果您不同意并且相信您有一个合法的用例来实现这个功能,那么有一种方法可以做到这一点,即使您更改了您希望查看的id。@david004方法的局限性是,除非在指令的链接函数运行时设置showdivwithid,否则它不会工作。如果在以后范围内的属性更改,DOM将不会正确地更新。

So here is a similar but different directive approach that will give you conditional hiding of an element based on its id, and will update if the keep-if-id attribute value changes:

这里有一种类似但不同的指令方法,它将根据元素的id对其进行有条件隐藏,如果keep-if-id属性值发生变化,它将进行更新:

app.directive("keepIfId", function(){
    return {
        restrict: 'A',
        transclude: true,
        scope: {
          keepIfId: '@'
        },
        template: '<div ng-transclude ng-if="idMatches"></div>',
        link: function (scope, element, atts) {
            scope.idMatches = false;
            scope.$watch('keepIfId', function (id) {
              scope.idMatches = atts.id === id;
            });
        }
    };
});

Here is the Plunkr to see it in action.

这是柱塞。

Update: Why your directives aren't working

更新:为什么你的指令不能工作

As mentioned in the comments on @david004's answer, you are definitely doing things in the wrong way (for AngularJS) by trying to create your article markup in blog.js using jQuery. You should instead be querying for the XML data in BlogController and populating a property on the scope with the results (in JSON/JS format) as an array. Then you use ng-repeat in your markup to repeat the markup for each item in the array.

正如@david004的回答中提到的,您试图在blog中创建文章标记,显然是在用错误的方式(对于AngularJS)做事情。js使用jQuery。您应该在BlogController中查询XML数据,并将结果(JSON/JS格式)作为数组填充到范围上的属性。然后在标记中使用ng-repeat来重复数组中的每个条目的标记。

However, if you must just "get it working", and with full knowledge that you are doing a hacky thing, and that the people who have to maintain your code may hate you for it, then know the following: AngularJS directives do not work until the markup is compiled (using the $compile service).

但是,如果你必须“得到工作”,和完整的知识,你是做一个出租汽车司机的事情,而且必须维护你代码的人可能恨你,然后知道以下:AngularJS指令不工作直到标记编译(使用$编译服务)。

Compilation happens automatically for you if you use AngularJS the expected, correct way. For example, when using ng-view, after it loads the HTML for the view, it compiles it.

如果您使用AngularJS的预期,正确的方法,编译就会自动发生。例如,在使用ng-view时,在加载视图的HTML之后,它会编译它。

But since you are going "behind Angular's back" and adding DOM without telling it, it has no idea it needs to compile your new markup.

但是,由于您正在“在棱角的背后”添加DOM而没有告知它,因此它不知道需要编译新的标记。

However, you can tell it to do so in your jQuery code (again, if you must).

但是,您可以在jQuery代码中告诉它这样做(如果您必须这样做的话)。

First, get a reference to the $compile service from the AngularJS dependency injector, $injector:

首先,从AngularJS依赖注入器获得$compile服务的引用,$injector:

var $compile = angular.element(document.body).injector().get('$compile');

Next, get the correct scope for the place in the DOM where you are adding these nodes:

接下来,获取要添加这些节点的DOM中的位置的正确范围:

var scope = angular.element('.blog-main').scope();

Finally, call $compile for each item, passing in the item markup and the scope:

最后,为每个项目调用$compile,传入项目标记和范围:

var compiledNode = $compile(itm)(scope);

This gives you back a compiled node that you should be able to insert into the DOM correctly:

这将返回一个编译后的节点,您应该能够正确地插入到DOM中:

$('.blog-main').append(compiledNode);

Note: I am not 100% sure you can compile before inserting into the DOM like this.

注意:在像这样插入DOM之前,我不能100%确定您是否可以进行编译。

So your final $.each() in blog.js should be something like:

所以你最后的$.each()在博客中。js应该是:

var $compile = angular.element(document.body).injector().get('$compile'),
    scope = angular.element('.blog-main').scope();
$.each(items, function(idx, itm) {
      var compiledNode = $compile(itm)(scope);
      $('.blog-main').append(compiledNode); 
      compiledNode.readmore();
});