Angular model/controller "hierarchy" 设置
Angular model/controller "hierarchy" setup
我正在开发一个 angular 应用程序,它本质上是我所有网站及其使用 ngboilerplate 的环境的管理面板。我需要设置一种函数和模型数据的层次结构,以便在没有设置 "parent" 的情况下任何 "child" controller/model 都无法工作。这是我要解释的内容的细分。
模型 -> 环境(产品、阶段、开发)
一旦 env selected 你就可以 select 网站
模型 -> 网站(所有网站来自
当前环境)一旦网站被 selected 你就会得到网站数据
模型 -> 站点(站点数据 json 包含诸如页面配置之类的内容
值等)
为这样的东西设置结构的正确方法是什么?我目前只是为页面内的每个路由使用单独的控制器和路由(ui-路由器)。我需要确保的主要功能是,如果环境随着站点 selected 而改变,站点的数据将从适当的环境重新加载。我在想我会使用 $watch 来确保这一点吗?任何关于最佳实践的 suggestions/tips 表示赞赏!
更新:在这里澄清一些细节:
我需要的主要模型"watched"是环境模型。根据设置的环境,我会调整正在使用的 api url 以及更改显示名称。它还会为 env 加载相应的站点列表(当前是静态 json 文件,但它可能是 api 调用)。这是我在问这个问题之前写的代码,当我得到 SitesCtrl 时,我意识到我可能做错了(或者无论如何都不是最佳的)。
Tools.js
angular.module( 'SupportBase.tools', [
'ui.router',
'placeholders',
'ui.bootstrap',
'SupportBase.tools.sites'
])
.config(function config( $stateProvider ) {
$stateProvider.state( 'tools', {
url: '/tools',
views: {
"main": {
controller: 'ToolsCtrl',
templateUrl: 'tools/tools.tpl.html'
},
"sites": {
controller: 'SitesCtrl',
templateUrl: 'tools/sites/sites.tpl.html'
}
},
data:{ pageTitle: 'Site Tools' }
});
})
.controller( 'ToolsCtrl', function ToolCtrl( $scope ) {
$scope.envModel = '';
});
Tools.tpl.hmtl
<div class="row">
<h1 class="page-header">
Site Tools
<small>For the lazy and impatient. {or the smart & productive}</small>
</h1>
</div>
<div class="row">
<div class="well col-md-5">
<h4>Current Working Environment:
<code class="env">{{envModel || 'null'}}</code></h4>
<div class="btn-group col-md-10 col-md-offset-2">
<label class="btn btn-primary" ui-sref="tools.sites({env: envModel})" ng-model="envModel" btn-radio="'Production'">Production</label>
<label class="btn btn-primary" ui-sref="tools.sites({env: envModel})" ng-model="envModel" btn-radio="'Stage'">Stage</label>
<label class="btn btn-primary" ui-sref="tools.sites({env: envModel})" ng-model="envModel" btn-radio="'QA'">QA</label>
<label class="btn btn-primary" ui-sref="tools.sites({env: envModel})" ng-model="envModel" btn-radio="'Dev'">Dev</label>
</div>
</div>
<div class="col-md-6" ui-view="sites"></div>
</div>
Sites.js
angular.module('SupportBase.tools.sites', [
'ui.router',
'placeholders',
'ui.bootstrap',
'SupportBase.tools'
])
.config(function config($stateProvider) {
$stateProvider.state('tools.sites', {
url: '/{env:[a-z]{1,10}}/sites',
views: {
"sites": {
controller: 'SitesCtrl',
templateUrl: 'tools/sites/sites.tpl.html'
}
},
data: {
pageTitle: 'Site Tools | SupportBase'
}
});
})
.controller('SitesCtrl', function SitesCtrl($scope, $stateParams, $http) {
$scope.env = $stateParams.env.toLowerCase();
$scope.disabled = $stateParams.env !== '' ? false : true;
if ($stateParams.env.toLowerCase() === 'production') {
$http.get('./src/app/sites/sites.json').success(function(data) {
$scope.sitesModel = data;
});
} else {
$scope.sitesModel = [$stateParams.env, 'something', 'face'];
}
});
Sites.tpl.html
<div class="well" collapse="disabled">
<h1>Site Selector</h1>
<h2>{{sitesModel}}</h2>
</div>
你调查过工厂吗?它们本质上是一种可以用作服务层的单例模式。每个控制器都可以依赖同一个工厂来获取数据并绑定到它,并且当数据更改时,更改将普遍更新
对于您要尝试做的事情仍然有点含糊。下面是一些帮助您入门的代码:
.constant('site_configuration', {
'greeting' : 'Hello User'
});
.factory('environment', function ($window, $q, $http, $log, $rootScope, secondary_service, site_configuration) {
// this way your child functions can call each other within the factory
var environment = {};
environment.prod = function() {
};
environment.dev = function(credentials) {
secondary_service.login(credentials).then(function(){
$log.log('hello')
site_configuration.greeting = 'Hello Dev Environment User!'
})
};
environment.stage = function(credentials) {
// do something
}
return environment;
})
.service('secondary_service', function ($window, $q, $log, $rootScope, $http) {
var myservice = {};
secondary_service.login = function() {
var deferred = $q.defer();
// some http call
deferred.resolve(true)
return deferred.promise;
};
return myservice;
})
我不使用 ui.router 所以我会非常通用,您可以根据需要申请。
此外,我还没有测试过这段确切的代码,因此请将其用作指南。
// setup constants to refer to and change when needed
.constant('site_config', {
'api_path' : '//prod.example.com',
'name' : 'Production',
'collection' : '/production'
});
.controller( 'homepage_controller', function($scope, $location, $log, site_config, environment){
var load_site = function() {
$scope.title = site_config.name;
environment.get().then(function(data){
$log.log('Do something with this ',data)
})
}
// looking for sandbox.example.com
if(window.location.host.indexOf('sandbox') > -1 ) {
environment.set('prod').then(function(){
$log.log('sandbox is loaded')
load_site()
})
// looking for qa.example.com
} else if (window.location.host.indexOf('qa') > -1) {
environment.set('qa').then(function(){
$log.log('qa is loaded')
load_site()
})
// looking for www.example.com
} else {
environment.set('prod').then(function(){
$log.log('production is loaded')
load_site()
})
}
})
.factory('environment', function ($window, $q, $http, $log, $rootScope, site_config) {
var environment = {};
environment.set = function(type) {
var deferred = $q.defer();
if(type == 'sandbox') {
site_config.api_path = '//sandbox.example.com';
site_config.name = 'Sandbox';
site_config.collection = '/development';
deferred.resolve(true)
}
if(type == 'qa') {
site_config.api_path = '//qa.example.com';
site_config.name = 'QA';
site_config.collection = '/qa';
deferred.resolve(true)
}
if(type == 'production') {
site_config.api_path = '//prod.example.com';
site_config.name = 'Production';
site_config.collection = '/production';
deferred.resolve(true)
}
return deferred.promise;
};
// just showing this as an example
environment.get = function() {
var deferred = $q.defer();
$http({
method:'GET',
url: site_config.api_path+site_config.collection
})
.success(function(data) {
deferred.resolve(data);
})
.error(function(status, headers, config) {
deferred.reject(false);
});
return deferred.promise;
}
return environment;
})
我正在开发一个 angular 应用程序,它本质上是我所有网站及其使用 ngboilerplate 的环境的管理面板。我需要设置一种函数和模型数据的层次结构,以便在没有设置 "parent" 的情况下任何 "child" controller/model 都无法工作。这是我要解释的内容的细分。
模型 -> 环境(产品、阶段、开发) 一旦 env selected 你就可以 select 网站
模型 -> 网站(所有网站来自 当前环境)一旦网站被 selected 你就会得到网站数据
模型 -> 站点(站点数据 json 包含诸如页面配置之类的内容 值等)
为这样的东西设置结构的正确方法是什么?我目前只是为页面内的每个路由使用单独的控制器和路由(ui-路由器)。我需要确保的主要功能是,如果环境随着站点 selected 而改变,站点的数据将从适当的环境重新加载。我在想我会使用 $watch 来确保这一点吗?任何关于最佳实践的 suggestions/tips 表示赞赏!
更新:在这里澄清一些细节:
我需要的主要模型"watched"是环境模型。根据设置的环境,我会调整正在使用的 api url 以及更改显示名称。它还会为 env 加载相应的站点列表(当前是静态 json 文件,但它可能是 api 调用)。这是我在问这个问题之前写的代码,当我得到 SitesCtrl 时,我意识到我可能做错了(或者无论如何都不是最佳的)。
Tools.js
angular.module( 'SupportBase.tools', [
'ui.router',
'placeholders',
'ui.bootstrap',
'SupportBase.tools.sites'
])
.config(function config( $stateProvider ) {
$stateProvider.state( 'tools', {
url: '/tools',
views: {
"main": {
controller: 'ToolsCtrl',
templateUrl: 'tools/tools.tpl.html'
},
"sites": {
controller: 'SitesCtrl',
templateUrl: 'tools/sites/sites.tpl.html'
}
},
data:{ pageTitle: 'Site Tools' }
});
})
.controller( 'ToolsCtrl', function ToolCtrl( $scope ) {
$scope.envModel = '';
});
Tools.tpl.hmtl
<div class="row">
<h1 class="page-header">
Site Tools
<small>For the lazy and impatient. {or the smart & productive}</small>
</h1>
</div>
<div class="row">
<div class="well col-md-5">
<h4>Current Working Environment:
<code class="env">{{envModel || 'null'}}</code></h4>
<div class="btn-group col-md-10 col-md-offset-2">
<label class="btn btn-primary" ui-sref="tools.sites({env: envModel})" ng-model="envModel" btn-radio="'Production'">Production</label>
<label class="btn btn-primary" ui-sref="tools.sites({env: envModel})" ng-model="envModel" btn-radio="'Stage'">Stage</label>
<label class="btn btn-primary" ui-sref="tools.sites({env: envModel})" ng-model="envModel" btn-radio="'QA'">QA</label>
<label class="btn btn-primary" ui-sref="tools.sites({env: envModel})" ng-model="envModel" btn-radio="'Dev'">Dev</label>
</div>
</div>
<div class="col-md-6" ui-view="sites"></div>
</div>
Sites.js
angular.module('SupportBase.tools.sites', [
'ui.router',
'placeholders',
'ui.bootstrap',
'SupportBase.tools'
])
.config(function config($stateProvider) {
$stateProvider.state('tools.sites', {
url: '/{env:[a-z]{1,10}}/sites',
views: {
"sites": {
controller: 'SitesCtrl',
templateUrl: 'tools/sites/sites.tpl.html'
}
},
data: {
pageTitle: 'Site Tools | SupportBase'
}
});
})
.controller('SitesCtrl', function SitesCtrl($scope, $stateParams, $http) {
$scope.env = $stateParams.env.toLowerCase();
$scope.disabled = $stateParams.env !== '' ? false : true;
if ($stateParams.env.toLowerCase() === 'production') {
$http.get('./src/app/sites/sites.json').success(function(data) {
$scope.sitesModel = data;
});
} else {
$scope.sitesModel = [$stateParams.env, 'something', 'face'];
}
});
Sites.tpl.html
<div class="well" collapse="disabled">
<h1>Site Selector</h1>
<h2>{{sitesModel}}</h2>
</div>
你调查过工厂吗?它们本质上是一种可以用作服务层的单例模式。每个控制器都可以依赖同一个工厂来获取数据并绑定到它,并且当数据更改时,更改将普遍更新
对于您要尝试做的事情仍然有点含糊。下面是一些帮助您入门的代码:
.constant('site_configuration', {
'greeting' : 'Hello User'
});
.factory('environment', function ($window, $q, $http, $log, $rootScope, secondary_service, site_configuration) {
// this way your child functions can call each other within the factory
var environment = {};
environment.prod = function() {
};
environment.dev = function(credentials) {
secondary_service.login(credentials).then(function(){
$log.log('hello')
site_configuration.greeting = 'Hello Dev Environment User!'
})
};
environment.stage = function(credentials) {
// do something
}
return environment;
})
.service('secondary_service', function ($window, $q, $log, $rootScope, $http) {
var myservice = {};
secondary_service.login = function() {
var deferred = $q.defer();
// some http call
deferred.resolve(true)
return deferred.promise;
};
return myservice;
})
我不使用 ui.router 所以我会非常通用,您可以根据需要申请。
此外,我还没有测试过这段确切的代码,因此请将其用作指南。
// setup constants to refer to and change when needed
.constant('site_config', {
'api_path' : '//prod.example.com',
'name' : 'Production',
'collection' : '/production'
});
.controller( 'homepage_controller', function($scope, $location, $log, site_config, environment){
var load_site = function() {
$scope.title = site_config.name;
environment.get().then(function(data){
$log.log('Do something with this ',data)
})
}
// looking for sandbox.example.com
if(window.location.host.indexOf('sandbox') > -1 ) {
environment.set('prod').then(function(){
$log.log('sandbox is loaded')
load_site()
})
// looking for qa.example.com
} else if (window.location.host.indexOf('qa') > -1) {
environment.set('qa').then(function(){
$log.log('qa is loaded')
load_site()
})
// looking for www.example.com
} else {
environment.set('prod').then(function(){
$log.log('production is loaded')
load_site()
})
}
})
.factory('environment', function ($window, $q, $http, $log, $rootScope, site_config) {
var environment = {};
environment.set = function(type) {
var deferred = $q.defer();
if(type == 'sandbox') {
site_config.api_path = '//sandbox.example.com';
site_config.name = 'Sandbox';
site_config.collection = '/development';
deferred.resolve(true)
}
if(type == 'qa') {
site_config.api_path = '//qa.example.com';
site_config.name = 'QA';
site_config.collection = '/qa';
deferred.resolve(true)
}
if(type == 'production') {
site_config.api_path = '//prod.example.com';
site_config.name = 'Production';
site_config.collection = '/production';
deferred.resolve(true)
}
return deferred.promise;
};
// just showing this as an example
environment.get = function() {
var deferred = $q.defer();
$http({
method:'GET',
url: site_config.api_path+site_config.collection
})
.success(function(data) {
deferred.resolve(data);
})
.error(function(status, headers, config) {
deferred.reject(false);
});
return deferred.promise;
}
return environment;
})