角度传递范围到ng-include

时间:2014-09-05 04:20:37

标签: javascript angularjs angularjs-ng-repeat angularjs-ng-include angularjs-ng-init

我有一个控制器,我写的是我在我的应用中使用ng-includeng-repeat的多个位置,如下所示:

<div
  ng-repeat="item in items"
  ng-include="'item.html'"
  ng-controller="ItemController"
></div>

在控制器/模板中,我希望item值存在,并且整个事情是围绕这个想法构建的。但是,现在我需要以稍微不同的方式使用控制器,而不需要ng-repeat,但仍然需要能够传入item。我看到ng-init并认为它可以做我需要的事情,就像这样:

<div
  ng-init="item = leftItem"
  ng-include="'item.html'"
  ng-controller="ItemController"
></div>
<div
  ng-init="item = rightItem"
  ng-include="'item.html'"
  ng-controller="ItemController"
></div>

但这似乎不起作用。任何人都有任何想法如何在像这样的单一实例中传入范围的变量?

编辑: 上面的控制器加载leftItemrightItem值,如下所示:

.controller('MainController', function($scope, ItemModel) {
    ItemModel.loadItems()
        .then(function(items) {
            $scope.$apply(function() {
                $scope.leftItem = items.left;
                $scope.rightItem = items.right;
            });
        });
});

8 个答案:

答案 0 :(得分:33)

您可以使用onload提供的ngInclude属性来执行此操作:

<div ng-include="'item.html'"
     ng-controller="ItemController"
     onload="item = rightItem">
</div>

Link to the documentation

修改

尝试在父范围内执行类似的操作:

$scope.dataHolder = {};

然后,当收到异步数据时,将数据存储在dataHolder

$scope.dataHolder.leftItem = items.leftItem;
$scope.dataHolder.rightItem = items.rightItem;

现在,当ng-include加载模板时,它将创建一个继承父项属性的子作用域。因此$scope.dataHolder将在此子范围中定义(最初作为空对象)。但是当收到异步数据时,对空对象的引用应该包含新接收的数据。

答案 1 :(得分:31)

晚会,但有一点角色&#39; hack&#39;在没有实施哑指令的情况下实现这一目标。

添加一个内置指令,可以扩展控制器的范围(例如ng-if),无论你在哪里使用ng-include,实际上都可以让你为所有包含的范围隔离变量名。

所以:

using System;
using System.Linq;
using System.Security.Cryptography;
using Org.BouncyCastle.Asn1;

namespace ConsoleApplication3
{
    class Program
    {
        static void Main(string[] args)
        {
            byte[] data = Convert.FromBase64String("dGF0b0Bmcm9td2luMzIuY29t");
            byte[] signature = Convert.FromBase64String("lWKRRgWBA2lBAfUvBS+54s9kmHTH3nJwcvYYmjCg5QpWQ9joY7Rzpq0zZjOhyxASXoAN4Vz8+mqSqPWi/4DFH7947ZWZSbopPfxiI7jjDRMAVymG0B+dRVjiMow48ZvhgP/FGSZqeLAei77Z0aAmwN2TBxkClqBpt9uy+nkI7V/TJGAbbLcWfiPWNVOGsU0smoFDQLlJjkocahNSOqjj+9PPFVqbc/VVHQWsSoq1ZxtCPILFwPCCtUCDITXrU/riGMFJ282p/3rfhDJKYis9/izR98/zgBLRoCew8zu8Za4UNWaHaR3HP/6voQI2NiVSKtss1VjvwjwXYIOh56yeSw==");
            byte[] publicKey = Convert.FromBase64String("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp6HzbSgZPkJPfZJWydFAKdzUWlQcGHCTZhghg8HwHOfRZp3QZ/iiDORVzdIlW6XYPz76aAn8Nxm/v4NbsQsFPbwIcc7CPOJe21VT+7f6ocZ4kef0dqxUOGuK1FynrqzsAeYoaeTW+w/HElXODOEzZs3CfyE3d4hy3TTM/mVyQGV1FO/hHWB/zXq7ryQ8hXP/ueJimmJvitB7UweemRxvEYfVx52VVAgzg1RqVWeRj8L/obfm0lwQtIAHdDOnIi/cwpsyKQNikjMsf4dFgt14fcOgFdSG06jB840GnOsRZM04CWZQ9ttwAvoNGK/zjriRYGySQ4Ey0K0l5G3UVr56mQIDAQAB");

            byte[] hash;
            using (SHA256 sha256 = SHA256.Create())
            {
                hash = sha256.ComputeHash(data);
            }

            bool b = false;
            var rsaParam = GetPublicKeyRSAParameters(publicKey);

            using (var rsa = new RSACryptoServiceProvider())
            {
                // Import public key
                rsa.ImportParameters(rsaParam);

                // Create signature verifier with the rsa key
                var signatureDeformatter = new RSAPKCS1SignatureDeformatter(rsa);

                // Set the hash algorithm to SHA256.
                signatureDeformatter.SetHashAlgorithm("SHA256");

                b = signatureDeformatter.VerifySignature(hash, signature);
            } 
        }

        public static RSAParameters GetPublicKeyRSAParameters(byte[] subjectPublicKeyInfoBytes)
        {
            var publicKeyObject = (DerSequence)Asn1Object.FromByteArray(subjectPublicKeyInfoBytes);
            var rsaPublicKeyParametersBitString = (DerBitString)publicKeyObject[1];

            var rsaPublicKeyParametersObject = (DerSequence)Asn1Object.FromByteArray(rsaPublicKeyParametersBitString.GetBytes());

            var modulus = ((DerInteger)rsaPublicKeyParametersObject[0]).Value.ToByteArray().Skip(1).ToArray();
            var exponent = ((DerInteger)rsaPublicKeyParametersObject[1]).Value.ToByteArray();

            return new RSAParameters() { Modulus = modulus, Exponent = exponent };
        }
    }
}

然后,您可以使用不同的项目将模板item.html多次绑定到项目变量。

Here is a plunker to achieve what you want

问题是项目在控制器范围内不断变化,只保留对每个onload指令中擦除的项目变量的一个引用。

引入扩展当前范围的指令,让您拥有所有ng-include的隔离范围。 因此,项目引用在所有扩展范围内都被保留并且是唯一的。

答案 2 :(得分:17)

我最终将其重写为指令并使用

绑定范围内的所需值
scope: {
    item: '='
}

答案 3 :(得分:11)

LOVE @ Tanin的回答。以一种非常优雅的方式同时解决以及许多问题。对于那些不喜欢我的人来说,不知道Coffeescript,这里是javascript ...

注意:由于我太难理解的原因,此代码要求您引用模板名称​​一次,而不是ng-include要求两次引用您的模板名称,即。 -(void) fetchContacts { CNContactStore *store = [[CNContactStore alloc] init]; [store requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) { if (granted == YES) { //keys with fetching properties NSArray *keys = @[CNContactFamilyNameKey, CNContactGivenNameKey, CNContactPhoneNumbersKey, CNContactImageDataKey]; NSString *containerId = store.defaultContainerIdentifier; NSPredicate *predicate = [CNContact predicateForContactsInContainerWithIdentifier:containerId]; NSError *error; NSArray *cnContacts = [store unifiedContactsMatchingPredicate:predicate keysToFetch:keys error:&error]; if (error) { NSLog(@"error fetching contacts %@", error); } else { NSString *phone; NSString *fullName; NSString *firstName; NSString *lastName; UIImage *profileImage; NSMutableArray *contactNumbersArray; for (CNContact *contact in cnContacts) { // copy data to my custom Contacts class. firstName = contact.givenName; lastName = contact.familyName; if (lastName == nil) { fullName=[NSString stringWithFormat:@"%@",firstName]; }else if (firstName == nil){ fullName=[NSString stringWithFormat:@"%@",lastName]; } else{ fullName=[NSString stringWithFormat:@"%@ %@",firstName,lastName]; } UIImage *image = [UIImage imageWithData:contact.imageData]; if (image != nil) { profileImage = image; }else{ profileImage = [UIImage imageNamed:@"acc_sett.png "]; } for (CNLabeledValue *label in contact.phoneNumbers) { phone = [label.value stringValue]; if ([phone length] > 0) { [contactNumbersArray addObject:phone]; } } NSDictionary* personDict = [[NSDictionary alloc] initWithObjectsAndKeys: fullName,@"fullName",profileImage,@"userImage",phone,@"PhoneNumbers", nil]; [_Contacts addObject:personDict]; NSLog(@"%@",phone); NSLog(@"%@",fullName); } dispatch_async(dispatch_get_main_queue(), ^{ [self.contacttableview reloadData]; }); } } }]; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ return [_Contacts count]; } - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{ return 1; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { NSDictionary* personDict = [_Contacts objectAtIndex:indexPath.row]; UITableViewCell *cell = nil; cell = [_contacttableview dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"cell"]; } cell.imageView.image = [personDict objectForKey:@"userImage"]; cell.textLabel.text = [personDict objectForKey:@"fullName"]; cell.detailTextLabel.text = [personDict objectForKey:@"phoneNumbers"]; return cell; } 代替<div ng-include-template="template-name.html" ... >

<div ng-include-template="'template-name.html'" ... >

答案 4 :(得分:10)

使用onload不是一个干净的解决方案,因为它会占用全局范围。如果你有更复杂的东西,它将开始失败。

ng-include不是可重用的,因为它可以访问全局范围。这有点奇怪。

上述情况并非如此。 ng-if with onload并不会影响全局范围

我们也不想为每种情况编写具体指令。

制作通用指令而不是ng-include是一种更清洁的解决方案。

理想用法如下:

<div ng-include-template="'item.html'" ng-include-variables="{ item: 'whatever' }"></div>
<div ng-include-template="'item.html'" ng-include-variables="{ item: variableWorksToo }"></div>

指令是:

.directive(
  'ngIncludeTemplate'
  () ->
    {
      templateUrl: (elem, attrs) -> attrs.ngIncludeTemplate
      restrict: 'A'
      scope: {
        'ngIncludeVariables': '&'
      }
      link: (scope, elem, attrs) ->
        vars = scope.ngIncludeVariables()
        for key, value of vars
          scope[key] = value
    }
)

您可以看到该指令不使用全局范围。相反,它从ng-include-variables读取对象,并将这些成员添加到其自己的本地范围。

我希望这是你想要的;它干净而且通用。

答案 5 :(得分:4)

我认为

ng-init对此更好。

<div ng-include='myFile.html' ng-init="myObject = myCtrl.myObject; myOtherObject=myCtrl.myOtherObject"/>

答案 6 :(得分:3)

上述内容不适用于二级属性,例如<div ng-include-template=... ng-include-variables="{ id: var.id }">。请注意var.id

更新指令(丑陋,但有效):

.directive('ngIncludeTemplate', function() {
  return {
    templateUrl: function(elem, attrs) { return attrs.ngIncludeTemplate; },
    restrict: 'A',
    scope: {
      'ngIncludeVariables': '&'
    },
    link: function(scope, elem, attrs) {
      var cache = scope.ngIncludeVariables();
      Object.keys(cache).forEach(function(key) {
        scope[key] = cache[key];
      });

      scope.$watch(
        function() {
          var val = scope.ngIncludeVariables();
          if (angular.equals(val, cache)) {
            return cache;
          }
          cache = val;
          return val;
        },
        function(newValue, oldValue) {
          if (!angular.equals(newValue, oldValue)) {
            Object.keys(newValue).forEach(function(key) {
              scope[key] = newValue[key];
            });
          }
        }
      );

    }
  };
});

答案 7 :(得分:1)

Maybe obvious update for Mike and Tanin answers - if you using inline templates as:

<script type="text/ng-template" id="partial">{{variable}}</script>

<div ng-include-template="'partial'" ng-include-variables="{variable: variable}"></div>

Then, in directive ngIncludeTemplate, replace

templateUrl: function(elem, attrs) { return attrs.ngIncludeTemplate; },  

With

template: function(elem, attrs) { return document.getElementById(attrs.ngIncludeTemplate.split("'")[1]).innerHTML },