Angular 1.5 组件通过ngRoute更新父控制器
Angular 1.5 component updating parent controller through ngRoute
我正在使用 ngRoute 创建一个 Angular 单页应用程序。想要移动到基于组件的版本。
问题是孤立的范围。我需要访问主控制器道具和方法。尝试使用绑定但不起作用。我找不到这个问题。这个应用程序在不使用组件的情况下运行良好。当我尝试将主页视图更改为组件时,它崩溃了。这些是代码的主要部分:
框架
<html ng-app="angularModule" >
<body ng-controller="angularController as angCtrl" >
<div ng-show="angCtrl.user.isLoggedIn" >Sign Out</div>
<div ng-hide="angCtrl.user.isLoggedIn" cd-visible="angCtrl.showSignIn">Sign In</div>
<div id="contentLayer" class="contentLayer" ng-view ></div>
主页模板
<h1 class="pageLabel" >HomePage</h1>
<blockquote>This can be anything. No bindings.</blockquote>
angularController
var app = angular.module ('angularModule', ['ngRoute'] );
app.directive ('cdVisible',
function () {
return function (scope, element, attr) {
scope.$watch (attr.cdVisible,
function (visible) {
element.css ('visibility', visible ? 'visible' : 'hidden');
}
);
};
}
);
app.config ( [ '$locationProvider', '$routeProvider',
function config ($locationProvider, $routeProvider) {
$locationProvider.hashPrefix ('!');
$routeProvider
.when ('/sign-in', {
templateUrl: '/ng-sign-in',
controller: signInController
})
... more routes
.when ('/home', {
template: '<home-page showSignIn="angCtrl.showSignIn" menuSelect="angCtrl.menuSelect" ></home-page>'
})
.otherwise ('/home');
}
]);
function homePageController () {
this.menuSelect ('Devices'); // this statement has no effect on angularController.menuSelection chrome shows it as an anonymous function
this.showSignIn = false; // this bombs: Expression 'undefined' in attribute 'showSignIn' used with directive 'homepage' is non-assignable!
}
app.component ('homePage', {
templateUrl: '/ng-homepage',
controller: homePageController,
bindings: {
menuSelect: '&',
showSignIn: '='
}
});
app.controller ('angularController', [ '$http', '$window', '$location',
function ($http, $window, $location) {
var self = this;
this.user = {
"isLoggedIn": false
};
this.showSignIn = true;
this.menuSelection = "";
this.errorMessage = "";
this.menuSelect =
function (selection) {
self.menuSelection = selection;
};
this.setUserData =
function (userData) {
self.user = userData;
};
this.setShowSignIn =
function (show) {
self.showSignIn = show;
};
this.menuSelect ('');
this.getUserData(); // I removed this for this post
}
]);
我在它抛出异常的地方添加了注释。主页控制器尝试更新 angularController 的模型。第一个什么都不做,第二个抛出异常。我究竟做错了什么?
首先 showSignIn
是一个原语,因此 angular 将以与 showSignIn="7+2"
完全相同的方式处理它。如果您需要在组件内部修改该值,那么您应该使用带有 showSignIn
属性.
的对象
现在 menuSelect
有点难,可能 Chrome 控制台显示类似
的内容
function (locals) {
return parentGet(scope, locals);
}
这是因为您只是将对 angCtrl.menuSelect
的引用传递给组件。
为了从 homePageController
内部执行 menuSelect
函数,您必须执行(在 HTML 中):
<home-page menu-select="angCtrl.menuSelect(myMsg)"></home-page>
然后在组件的控制器中这样调用它:
this.menuSelect({ myMsg:"Devices" })
HTML中的(myMsg)
是调用angular到return这个引用,那么在执行中我们传参数{ myMsg:"Devices" }
给匹配我们刚刚做的参考中的参数。
您可以查看 以更详细地解释它。
在阅读您的回答的过程中,我突然犯了一个错误:/home 路由的主页组件应该使用 kebab case show-sign-in menu-select 属性而不是 lower-camelCase正如最初编码的那样。
您的建议都奏效了。谢谢。在没有组件的情况下,我使用原型继承来访问父范围中的属性和方法。由于 javascript 原型继承的性质,在父作用域中修改标量的唯一方法是在父作用域上调用 setter 方法。显然这里也适用类似的东西。 javascript.
中有关 prototypal inheritance 的更多信息
这是一个概念验证练习。我想测试我从组件更新父作用域中的属性和对象以及在父作用域中执行方法的能力。此示例以两种不同的方式更新父作用域中的标量:
- 将其粘贴到对象中,绑定到对象并使用组件中的对象引用它,就像使用 loginData.showSignIn 布尔值
一样
- 在父作用域中构建一个 setter 方法并绑定到该方法并从组件调用 setter 就像使用 menuSelect 完成的那样(实际上只不过是一个 setter对于菜单选择)
并演示了在执行此操作时调用函数。
最终工作代码为:(首页模板不变)
框架
<html ng-app="angularModule" >
<body ng-controller="angularController as angCtrl" >
<div ng-show="angCtrl.user.isLoggedIn" >Sign Out</div>
<div ng-hide="angCtrl.user.isLoggedIn" cd-visible="angCtrl.loginData.showSignIn">Sign In</div>
<div id="contentLayer" class="contentLayer" ng-view ></div>
angularController
var app = angular.module ('angularModule', ['ngRoute'] );
app.directive ('cdVisible',
function () {
return function (scope, element, attr) {
scope.$watch (attr.cdVisible,
function (visible) {
element.css ('visibility', visible ? 'visible' : 'hidden');
}
);
};
}
);
app.config ( [ '$locationProvider', '$routeProvider',
function config ($locationProvider, $routeProvider) {
$locationProvider.hashPrefix ('!');
$routeProvider
.when ('/sign-in', {
templateUrl: '/ng-sign-in',
controller: signInController
})
... more routes
.when ('/home', {
template: '<home-page login-data="angCtrl.loginData" menu-select="angCtrl.menuSelect(mySelection)" ></home-page>'
})
.otherwise ('/home');
}
]);
function homePageController () {
this.menuSelect ( { mySelection: 'Overview' });
this.loginData.showSignIn = true;
}
app.component ('homePage', {
templateUrl: '/ng-homepage',
controller: homePageController,
restrict: 'E',
bindings: {
menuSelect: '&',
loginData: '='
}
});
app.controller ('angularController', [ '$http', '$window', '$location',
function ($http, $window, $location) {
var self = this;
this.user = {
"isLoggedIn": false
};
this.loginData = {
"showSignIn": false
};
this.menuSelection = "";
this.errorMessage = "";
this.menuSelect =
function (selection) {
self.menuSelection = selection;
};
this.setUserData =
function (userData) {
self.user = userData;
};
this.setShowSignIn =
function (show) {
self.showSignIn = show;
};
this.menuSelect ('');
this.getUserData(); // I removed this for this post
}
]);
我正在使用 ngRoute 创建一个 Angular 单页应用程序。想要移动到基于组件的版本。
问题是孤立的范围。我需要访问主控制器道具和方法。尝试使用绑定但不起作用。我找不到这个问题。这个应用程序在不使用组件的情况下运行良好。当我尝试将主页视图更改为组件时,它崩溃了。这些是代码的主要部分:
框架
<html ng-app="angularModule" >
<body ng-controller="angularController as angCtrl" >
<div ng-show="angCtrl.user.isLoggedIn" >Sign Out</div>
<div ng-hide="angCtrl.user.isLoggedIn" cd-visible="angCtrl.showSignIn">Sign In</div>
<div id="contentLayer" class="contentLayer" ng-view ></div>
主页模板
<h1 class="pageLabel" >HomePage</h1>
<blockquote>This can be anything. No bindings.</blockquote>
angularController
var app = angular.module ('angularModule', ['ngRoute'] );
app.directive ('cdVisible',
function () {
return function (scope, element, attr) {
scope.$watch (attr.cdVisible,
function (visible) {
element.css ('visibility', visible ? 'visible' : 'hidden');
}
);
};
}
);
app.config ( [ '$locationProvider', '$routeProvider',
function config ($locationProvider, $routeProvider) {
$locationProvider.hashPrefix ('!');
$routeProvider
.when ('/sign-in', {
templateUrl: '/ng-sign-in',
controller: signInController
})
... more routes
.when ('/home', {
template: '<home-page showSignIn="angCtrl.showSignIn" menuSelect="angCtrl.menuSelect" ></home-page>'
})
.otherwise ('/home');
}
]);
function homePageController () {
this.menuSelect ('Devices'); // this statement has no effect on angularController.menuSelection chrome shows it as an anonymous function
this.showSignIn = false; // this bombs: Expression 'undefined' in attribute 'showSignIn' used with directive 'homepage' is non-assignable!
}
app.component ('homePage', {
templateUrl: '/ng-homepage',
controller: homePageController,
bindings: {
menuSelect: '&',
showSignIn: '='
}
});
app.controller ('angularController', [ '$http', '$window', '$location',
function ($http, $window, $location) {
var self = this;
this.user = {
"isLoggedIn": false
};
this.showSignIn = true;
this.menuSelection = "";
this.errorMessage = "";
this.menuSelect =
function (selection) {
self.menuSelection = selection;
};
this.setUserData =
function (userData) {
self.user = userData;
};
this.setShowSignIn =
function (show) {
self.showSignIn = show;
};
this.menuSelect ('');
this.getUserData(); // I removed this for this post
}
]);
我在它抛出异常的地方添加了注释。主页控制器尝试更新 angularController 的模型。第一个什么都不做,第二个抛出异常。我究竟做错了什么?
首先 showSignIn
是一个原语,因此 angular 将以与 showSignIn="7+2"
完全相同的方式处理它。如果您需要在组件内部修改该值,那么您应该使用带有 showSignIn
属性.
现在 menuSelect
有点难,可能 Chrome 控制台显示类似
function (locals) {
return parentGet(scope, locals);
}
这是因为您只是将对 angCtrl.menuSelect
的引用传递给组件。
为了从 homePageController
内部执行 menuSelect
函数,您必须执行(在 HTML 中):
<home-page menu-select="angCtrl.menuSelect(myMsg)"></home-page>
然后在组件的控制器中这样调用它:
this.menuSelect({ myMsg:"Devices" })
HTML中的(myMsg)
是调用angular到return这个引用,那么在执行中我们传参数{ myMsg:"Devices" }
给匹配我们刚刚做的参考中的参数。
您可以查看
在阅读您的回答的过程中,我突然犯了一个错误:/home 路由的主页组件应该使用 kebab case show-sign-in menu-select 属性而不是 lower-camelCase正如最初编码的那样。
您的建议都奏效了。谢谢。在没有组件的情况下,我使用原型继承来访问父范围中的属性和方法。由于 javascript 原型继承的性质,在父作用域中修改标量的唯一方法是在父作用域上调用 setter 方法。显然这里也适用类似的东西。 javascript.
中有关 prototypal inheritance 的更多信息这是一个概念验证练习。我想测试我从组件更新父作用域中的属性和对象以及在父作用域中执行方法的能力。此示例以两种不同的方式更新父作用域中的标量:
- 将其粘贴到对象中,绑定到对象并使用组件中的对象引用它,就像使用 loginData.showSignIn 布尔值 一样
- 在父作用域中构建一个 setter 方法并绑定到该方法并从组件调用 setter 就像使用 menuSelect 完成的那样(实际上只不过是一个 setter对于菜单选择)
并演示了在执行此操作时调用函数。
最终工作代码为:(首页模板不变)
框架
<html ng-app="angularModule" >
<body ng-controller="angularController as angCtrl" >
<div ng-show="angCtrl.user.isLoggedIn" >Sign Out</div>
<div ng-hide="angCtrl.user.isLoggedIn" cd-visible="angCtrl.loginData.showSignIn">Sign In</div>
<div id="contentLayer" class="contentLayer" ng-view ></div>
angularController
var app = angular.module ('angularModule', ['ngRoute'] );
app.directive ('cdVisible',
function () {
return function (scope, element, attr) {
scope.$watch (attr.cdVisible,
function (visible) {
element.css ('visibility', visible ? 'visible' : 'hidden');
}
);
};
}
);
app.config ( [ '$locationProvider', '$routeProvider',
function config ($locationProvider, $routeProvider) {
$locationProvider.hashPrefix ('!');
$routeProvider
.when ('/sign-in', {
templateUrl: '/ng-sign-in',
controller: signInController
})
... more routes
.when ('/home', {
template: '<home-page login-data="angCtrl.loginData" menu-select="angCtrl.menuSelect(mySelection)" ></home-page>'
})
.otherwise ('/home');
}
]);
function homePageController () {
this.menuSelect ( { mySelection: 'Overview' });
this.loginData.showSignIn = true;
}
app.component ('homePage', {
templateUrl: '/ng-homepage',
controller: homePageController,
restrict: 'E',
bindings: {
menuSelect: '&',
loginData: '='
}
});
app.controller ('angularController', [ '$http', '$window', '$location',
function ($http, $window, $location) {
var self = this;
this.user = {
"isLoggedIn": false
};
this.loginData = {
"showSignIn": false
};
this.menuSelection = "";
this.errorMessage = "";
this.menuSelect =
function (selection) {
self.menuSelection = selection;
};
this.setUserData =
function (userData) {
self.user = userData;
};
this.setShowSignIn =
function (show) {
self.showSignIn = show;
};
this.menuSelect ('');
this.getUserData(); // I removed this for this post
}
]);