我们正在使用为银行构建的Angular应用程序来应对性能问题。
不幸的是,显示代码片段违反了合同。 无论如何,我可以描述正在进行的一些主要问题,我希望可以推荐最佳实践。
应用结构:
如果您看一下时间线。 我们在jQuery parse html方法,jQuery重新计算stye方法,GC事件(垃圾收集)上花费了大量时间。 我想将这些最小化应该可以加快速度。 它们都是Angular生命周期的一部分,但是可能有更好的方法来避免它们。 这是探查器的一些屏幕截图:
最终,随着重复表单的数量超过5,该应用程序变得迟钝。每种表单相对于其他表单都没有关系。 我们试图不监视表单之间的任何共享属性。
我在将元素拖到可伸缩div容器上时遇到了一个小问题。
一旦元素实际位于容器中,这些元素就可以正常拖动并按应有的方式工作。
拖到可伸缩容器上的较大元素不会有太大问题。
但是,当拖动较小的元素时,您会看到鼠标不再与该元素连接,当鼠标放下时,鼠标会从应该放下的位置掉落一点。
我试图找到一种解决方案,使鼠标停留在元素上,并且将其放置在应该放置的位置。
我已经一点点解决了问题,您可以在下面看到,但这是使我生气的难题的最后一部分。 如果有人有时间伸出援助之手,将不胜感激。
这是一个Codepen-单击并拖动两个蓝色元素到白色容器中进行尝试
这将有助于确保可放置区域可与缩放容器一起使用。
$.ui.ddmanager.prepareOffsets = function(t, event) {
var i, j, m = $.ui.ddmanager.droppables[t.options.scope] || [],
type = event ? event.type : null,
list = (t.currentItem || t.element).find(":data(ui-droppable)").addBack();
droppablesLoop: for (i = 0; i < m.length; i++) {
if (m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0], (t.currentItem || t.element)))) {
continue;
}
for (j = 0; j < list.length; j++) {
if (list[j] === m[i].element[0]) {
m[i].proportions().height = 0;
continue droppablesLoop;
}
}
m[i].visible = m[i].element.css("display") !== "none";
if (!m[i].visible) {
continue;
}
if (type === "mousedown") {
m[i]._activate.call(m[i], event);
}
m[i].offset = m[i].element.offset();
m[i].proportions({
width: m[i].element[0].offsetWidth * percent,
height: m[i].element[0].offsetHeight * percent
});
}
};
使元素在缩放容器上可调整大小
function resizeFix(event, ui) {
var changeWidth = ui.size.width - ui.originalSize.width,
newWidth = ui.originalSize.width + changeWidth / percent,
changeHeight = ui.size.height - ui.originalSize.height,
newHeight = ui.originalSize.height + changeHeight / percent;
ui.size.width = newWidth;
ui.size.height = newHeight;
}
使其在缩放容器上起作用
function dragFix(event, ui) {
var containmentArea = $("#documentPage_"+ui.helper.parent().parent().attr('id').replace(/^(\w+)_/, "")),
contWidth = containmentArea.width(), contHeight = containmentArea.height();
ui.position.left = Math.max(0, Math.min(ui.position.left / percent , contWidth - ui.helper.width()));
ui.position.top = Math.max(0, Math.min(ui.position.top / percent, contHeight- ui.helper.height()));
}
创建一个可以拖动到框上的可拖动元素。
.directive('draggableTypes', function() {
return {
restrict:'A',
link: function(scope, element, attrs) {
element.draggable({
zIndex:3000,
appendTo: 'body',
helper: function(e, ui){
var formBox = angular.element($("#formBox"));
percent = formBox.width() / scope.templateData.pdf_width;
if(element.attr('id') == 'textbox_item')
return $('<div class="text" style="text-align:left;font-size:14px;width:200px;height:20px;line-height:20px;">New Text Box.</div>').css({ 'transform': 'scale(' + percent + ')', '-moz-transform': 'scale(' + percent + ')', '-webkit-transform': 'scale(' + percent + ')', '-ms-transform': 'scale(' + percent + ')'});
if(element.attr('id') == 'sm_textbox_item')
return $('<div class="text" style="text-align:left;font-size:14px;width:5px;height:5px;line-height:20px;"></div>').css({ 'transform': 'scale(' + percent + ')', '-moz-transform': 'scale(' + percent + ')', '-webkit-transform': 'scale(' + percent + ')', '-ms-transform': 'scale(' + percent + ')'});
}
});
}
};
})
创建可能已经在框中的可拖动/可调整大小的元素,并将拖动/调整大小的修复方法应用于这些元素
.directive('textboxDraggable', function() {
return {
restrict:'A',
link: function(scope, element, attrs) {
element.draggable({
cursor: "move",
drag: dragFix,
start: function(event, ui) {
var activeId = element.attr('id');
scope.activeElement.id = activeId;
scope.activeElement.name = scope.templateItems[activeId].info.name;
scope.$apply();
}
});
element.resizable({
minWidth: 25,
minHeight: 25,
resize: resizeFix,
stop: function( event, ui ) {
var activeId = element.attr('id');
scope.activeElement.duplicateName = false;
scope.activeElement.id = activeId;
scope.activeElement.name = scope.templateItems[activeId].info.name;
scope.templateItems[activeId]['style']['width'] = element.css('width');
scope.templateItems[activeId]['style']['height'] = element.css('height');
scope.$apply();
}
})
}
};
})
放下物品时会发生什么
.directive('droppable', function($compile) {
return {
restrict: 'A',
link: function(scope,element,attrs){
element.droppable({
drop:function(event,ui) {
var draggable = angular.element(ui.draggable),
draggable_parent = draggable.parent().parent(),
drag_type = draggable.attr('id'),
documentBg = element,
x = ui.offset.left,
y = ui.offset.top,
element_top = (y - documentBg.offset().top - draggable.height() * (percent - 1) / 2) / percent,
element_left = (x - documentBg.offset().left - draggable.width() * (percent - 1) / 2) / percent,
timestamp = new Date().getTime();
//just get the document page of where the mouse is if its a new element
if(draggable_parent.attr('id') == 'template_builder_box_container' || draggable_parent.attr('id') == 'template_builder_container')
var documentPage = documentBg.parent().parent().attr('id').replace(/^(\w+)_/, "");
//if you are dragging an element that was already on the page, get parent of draggable and not parent of where mouse is
else var documentPage = draggable_parent.parent().parent().attr('id').replace(/^(\w+)_/, "");
if(drag_type == "textbox_item")
{
scope.activeElement.id = scope.templateItems.push({
info: {'page': documentPage,'name': 'textbox_'+timestamp, 'type': 'text'},
style: {'text-align':'left','font-size':'14px','top':element_top+'px','left':element_left+'px', 'width':'200px', 'height':'20px'}
}) - 1;
scope.activeElement.name = 'textbox_'+timestamp;
}
else if(drag_type == "sm_textbox_item")
{
scope.activeElement.id = scope.templateItems.push({
info: {'page': documentPage,'name': '', 'type': 'text'},
style: {'text-align':'left','font-size':'14px','top':element_top+'px','left':element_left+'px', 'width':'5px', 'height':'5px'}
}) - 1;
scope.activeElement.name = 'textbox_'+timestamp;
}
else {
scope.templateItems[scope.activeElement.id]['style']['top'] = draggable.css('top');
scope.templateItems[scope.activeElement.id]['style']['left'] = draggable.css('left');
}
scope.$apply();
}
});
}
};
})
最后但并非最不重要的是,我的控制器
.controller('testing', function($scope, $rootScope, $state, $stateParams) {
$scope.templateItems = [];
$scope.activeElement = { id: undefined, name: undefined };
$scope.templateData = {"id":"12345", "max_pages":1,"pdf_width":385,"pdf_height":800};
$scope.clickElement = function(index) { $scope.activeElement = { id: index, name: $scope.templateItems[index].info.name } }
});
这是我的HTML的基础
<div id="formBox" ng-style="formbox(templateData.pdf_width)" zoom>
<div class="trimSpace" ng-style="trimSpace(templateData.pdf_width)" zoom>
<div id="formScale" ng-style="formScale(templateData.pdf_width)" zoom>
<form action="#" id="{{ templateData.id }}_form">
<div ng-repeat="key in [] | range:templateData.max_pages">
<div class="formContainer" id="{{ templateData.id + '_' + (key+1) }}" ng-style="{width: templateData.pdf_width+'px', height: templateData.pdf_height+'px'}">
<div class="formContent">
<div class="formBackground" id="documentPage_{{ (key+1) }}" droppable>
<div ng-hide="preview" ng-repeat="item in templateItems">
<div ng-if="item.info.page == (key+1) && item.info.type == 'text'" id="{{ $index }}" data-type="{{ item.info.type }}" ng-click="clickElement($index)" class="text" ng-style="item.style" textbox-draggable>{{ item.info.name }}</div>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
我使用加载一些二进制数据
$http.post(url, data, { responseType: "arraybuffer" }).success(
function (data) { /* */ });
如果发生错误,服务器将以错误的JSON对象响应,例如
{ "message" : "something went wrong!" }
有什么方法可以得到与成功响应不同类型的错误响应?
$http.post(url, data, { responseType: "arraybuffer" })
.success(function (data) { /* */ })
.error(function (data) { /* how to access data.message ??? */ })
在量角器端到端测试中,我想使用我的代码element(by.css(...))检查某个元素是否存在:
var myElement = element(by.css('.elementClass'));
expect(myElement).toBeUndefined;
该测试失败,它说:
Expected { locator_ : { using : 'css selector', value : 'div[ng-switch-
when="resultNav"]' }, parentElementFinder_ : null, opt_actionResult_ :
undefined, opt_index_ : undefined, click : Function, sendKeys : Function,
getTagName : Function, getCssValue : Function, getAttribute : Function, getText
: Function, getSize : Function, getLocation : Function, isEnabled : Function,
isSelected : Function, submit : Function, clear : Function, isDisplayed :
Function, getOuterHtml : Function, getInnerHtml : Function, toWireValue :
Function } to be undefined.
之后,我尝试使用一个承诺:
element(by.css('.elementClass')).then( functtion(data) {
expect(data.getText()).toBeUndefined();
});
这将导致错误:
错误:使用定位器By.CssSelector(...)未找到任何元素
是的,我知道将找不到任何元素,但是如何使用element(element(by.css())
)创建工作测试?
有谁知道如何实现这一目标? 还是element(by.css())
不是此处使用的方法?
为什么在下面的示例中,初始渲染值为{{ person.name }}
而不是David
? 您将如何解决?
这里的例子
HTML:
<body ng-controller="MyCtrl">
<div contenteditable="true" ng-model="person.name">{{ person.name }}</div>
<pre ng-bind="person.name"></pre>
</body>
JS:
app.controller('MyCtrl', function($scope) {
$scope.person = {name: 'David'};
});
app.directive('contenteditable', function() {
return {
require: 'ngModel',
link: function(scope, element, attrs, ctrl) {
// view -> model
element.bind('blur', function() {
scope.$apply(function() {
ctrl.$setViewValue(element.html());
});
});
// model -> view
ctrl.$render = function() {
element.html(ctrl.$viewValue);
};
// load init value from DOM
ctrl.$setViewValue(element.html());
}
};
});
我想检测在单击复选框时是否选中了该复选框。
这就是我所拥有的:
<input type="checkbox" ng-model="answers[item.questID]" ng-change="stateChanged()" />
然后在控制器中,我有:
$scope.stateChanged = function () {
alert('test');
}
我可以在选中/取消选中时触发警报,但是如何检测复选框的状态? 我做了一些研究以找到类似的问题,但是我无法获得所需的东西。
谢谢,拉齐奥
在Angular 1.2中,ui.router
是一个单独的模块,因此您可以改用其他社区路由器,例如ngRoute
。
我正在编写一个开放源代码模块,旨在用于多种不同的路由器实现。 那么如何检查哪个路由器已加载或存在?
我正在模块的工厂内进行以下操作,但是它无法按我期望的方式工作:
if (angular.module("ngRoute"))
// Do ngRoute-specific stuff.
else if (angular.module("ui.router"))
// Do ui.router-specific stuff.
无论哪个模块未加载,都会引发错误。 例如,如果应用程序使用的是ui.router
,则ngRoute
检查会引发以下错误:
未捕获的错误:[$ injector:nomod]模块'ngRoute'不可用! 您可能拼错了模块名称,或者忘记了加载它。 如果 注册模块确保您将依赖项指定为 第二个论点。
我想在页面上放置多个日期选择器。 但是,使用UI-Bootstrap的默认解决方案是不可能的,无法打开任何一个日期选择器。 彼此之间的冲突。 这是我的代码:
<div>
<div class="form-horizontal pull-left">
<input type="text" datepicker-popup="dd-MMMM-yyyy" ng-model="dt" is-open="opened" min="minDate" max="'2015-06-22'" datepicker-options="dateOptions" date-disabled="disabled(date, mode)" ng-required="true"/>
<button class="btn" ng-click="open()"><span class="glyphicon glyphicon-calendar"></span></button>
</div>
<div class="form-horizontal pull-left">
<input type="text" datepicker-popup="dd-MMMM-yyyy" ng-model="dt" is-open="opened" min="minDate" max="'2015-06-22'" datepicker-options="dateOptions" date-disabled="disabled(date, mode)" ng-required="true" />
<button class="btn" ng-click="open()"><span class="glyphicon glyphicon-calendar"></span></button>
</div>
<button type="submit" class="btn btn-default">Submit</button>
</div>
我只是从站点[http://angular-ui.github.io/bootstrap/#/datepicker。]复制/粘贴了日期选择器代码。它们彼此冲突。 当我单击<input>
字段以打开日期选择器时,任何人都无法正确打开,两者均打开一秒钟,然后立即消失。
我如何在一个页面上有多个日期选择器?
让我们看一下我的指令:
angular.module('main').directive('datepicker', [
function() {
return {
require: '?ngModel',
link: function(scope, element, attributes, ngModel) {
ngModel.$modelValue = 'abc'; // this does not work
// how do I change the value of the model?
那么,如何更改ng-model的值?
我按照本教程安装了量角器,当我使用webdriver-manager更新时,它说:
selenium standalone is up to date.
chromedriver is up to date.
您在我尝试进行量角器测试时说:
C:\Users\****\AppData\Roaming\npm\node_modules\protractor\lib\driverProviders\local.dp.js:42
throw new Error('Could not find chromedriver at ' +
^
Error: Could not find chromedriver at C:\Users\****\AppData\Roaming\npm\node_modules\protractor\selenium\chromedriver.exe
at LocalDriverProvider.addDefaultBinaryLocs_ (C:\Users\****\AppData\Roaming\npm\node_modules\protractor\lib\driverProviders\local.dp.js:42:15)
at LocalDriverProvider.setupEnv (C:\Users\****\AppData\Roaming\npm\node_modules\protractor\lib\driverProviders\local.dp.js:59:8)
at Runner.run (C:\Users\****\AppData\Roaming\npm\node_modules\protractor\lib\runner.js:308:31)
at process.<anonymous> (C:\Users\****\AppData\Roaming\npm\node_modules\protractor\lib\runFromLauncher.js:32:14)
at process.EventEmitter.emit (events.js:98:17)
at handleMessage (child_process.js:318:10)
at Pipe.channel.onread (child_process.js:345:11)
[launcher] Runner Process Exited With Error Code: 8
我检查了local.dp.js,发现它试图从.. \ node_modules \ protractor \ selenium \ chromedriver加载chromedriver,但是只有一个空的zip文件,名为chromedriver_2.9。
因此,我手动下载了chromedriver并将其复制到此位置,从而产生了新错误:
C:\Users\****\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\webdriver\promise.js:1549
throw error;
^
Error: Server exited with 1
at Error (<anonymous>)
at ChildProcess.onServerExit (C:\Users\****\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\remote\index.js:193:11)
at ChildProcess.g (events.js:180:16)
at ChildProcess.EventEmitter.emit (events.js:98:17)
at Process.ChildProcess._handle.onexit (child_process.js:797:12)
[launcher] Runner Process Exited With Error Code: 8
任何人有想法吗?
我在控制器中看到$ scope有$ root,这是什么? 与可以注入控制器的$ rootScope有何不同?
我是一个有角度的新手,我在角度验证形式验证指令的工作方式上遇到了麻烦。
我知道我可以很容易地将指令添加到各个字段,但是我试图添加一个验证,该验证将比较两个表单字段(两者都是模型的元素)。
这是一个表单框架:
<form name="edit_form" >
<input name="min" type="number" ng-model="field.min"/>
<input name="max" type="number" ng-model="field.max"/>
</form>
<div class="error" ng-show="edit_form.min.$dirty || edit_form.max.$dirty">
<small class="error" ng-show="(what goes here?)">
Min cannot exceed max
</small>
</div>
简而言之,如果min
和max
都具有值但min > max
都具有值,我想编写一个指令并将其用于显示/隐藏此small.error
。如何访问一个指令中的两个字段? 指令是这项工作的正确工具吗?
这个问题已经在这里有了答案:
有什么方法可以使用Angularjs管理用户会话吗?,我的意思是::
拦截器可以解决这个问题吗? 你能举个例子吗?
提前致谢。
所以我对Angular js vs Express js的目标有些困惑。 根据我的理解,我们使用Node.js来提供Angular js的服务,但是我们并不完全受限于或被迫使用Node.js来提供服务。 另一方面,Express js似乎完成了与更传统的MVC框架类似的任务。
那么Angular Js是一种非特定于服务器的MVC框架吗? 这是否限制了Angular js后端服务器功能或易用性?
我正在工具栏中使用FAB快速拨号。 但是,我无法使其浮动在工具栏的右侧。 我尝试过样式:“ float:right”,但没有运气。 还尝试了flex offset =“ 55”,但是在调整窗口大小时不起作用。 本质上,无论窗口大小如何,我都希望按钮位于蓝色工具栏容器的最右边。 在这方面的任何帮助将不胜感激。 请参见下面的照片和代码:
<md-toolbar layout-fill layout-padding layout="row" style="background-color: #3F51B5;color:white;text-align:text-center;">
<div layout="row">
<i class="fa fa-users fa-2x" flex></i>
<h1 class="md-title" style="color:white">Org Chart</h1>
</div>
<div class="lock-size" flex offset="55">
<md-fab-speed-dial md-direction="left" ng-class="md-fling">
<md-fab-trigger>
<md-button aria-label="menu" class="md-fab md-accent">
<md-tooltip>
Actions
</md-tooltip>
<md-icon md-svg-src="img/icons/ic_view_module_48px.svg"></md-icon>
</md-button>
</md-fab-trigger>
<md-fab-actions>
<md-button aria-label="view" class="md-fab md-raised md-mini" >
<md-tooltip>
View Chart
</md-tooltip>
<md-icon md-svg-src="" style="color:black" ng-show="cDP.read" ng-click="paneShowFn('read')"></md-icon>
</md-button>
<md-button aria-label="add" class="md-fab md-raised md-mini" >
<md-tooltip>
Add Chart
</md-tooltip>
<md-icon md-svg-src="img/icons/ic_add_48px.svg" style="color:black" ng-show="cDP.insert" ng-click="paneShowFn('insert')"></md-icon>
</md-button>
<md-button aria-label="Settings" class="md-fab md-raised md-mini" >
<md-tooltip>
Security Access
</md-tooltip>
<md-icon md-svg-src="img/icons/ic_add_48px.svg" style="color:black" ng-show="cDP.permission" ng-click="paneShowFn('permission')"></md-icon>
</md-button>
<md-button aria-label="edit" class="md-fab md-raised md-mini" style="color:black" ng-show="cDP.update" ng-click="paneShowFn('update')">
<md-tooltip>
Edit Chart
</md-tooltip>
<md-icon md-svg-src="img/icons/ic_edit_48px.svg" style="color:black"></md-icon>
</md-button>
</md-fab-actions>
</md-fab-speed-dial>
</div>
</md-toolbar>
我正在看有角度的1.2源代码,我很好奇为什么某些函数以两个美元符号开头。 这是某种约定吗?
var theApp = angular.module('theApp', []);
var app = angular.module('theApp', ['ui.bootstrap']);
app.controller('MenuSideController', ['$scope','SnazzyService','$modal','$log', function($scope, SnazzyService, $modal, $log) {
$scope.user.zoomlvl = '2';
}]);
我有上面的控制器,它设置了MenuSideController
,我只能从内部访问这些值。
但是我在某处看到可以使用下面的内容访问MenuSideController
,但是当我valZoom
$scope.user.zoomlvl
不存在时。
我无法弄清楚如何访问MenuSideController
$ scope并使用valZoom
变量进行更新。
var appElement = document.querySelector('[ng-app=theApp]');
var $scope = angular.element(appElement).scope();
console.log($scope);
$scope.$apply(function() {
$scope.user.zoomlvl = valZoom;
});
我想在angular 2中打印HTML模板。我对此进行了探索,我在angularjs 1中得到了解决方案。在Angularjs 1中打印HTML模板。
任何建议将不胜感激
用AngularJS应用提供适当的404的最佳方法是什么?
一点背景:我正在构建一个Angular应用程序,并选择使用
$locationProvider.html5Mode(true);
因为我希望这些网址看起来自然(并且与多页“传统”网络应用程序没有区别)。
在服务器端(一个简单的Python Flask应用程序),我有一个包罗万象的处理程序,它将所有内容重定向到有角度的应用程序:
@app.route('/', defaults={'path': ''})
@app.route('/<path>')
def index(path):
return make_response(open('Ang/templates/index.html').read())
现在,我试图找出如何处理404错误。 我见过的大多数Angular应用程序都执行以下操作:
.otherwise({ redirectTo: '/' })
这意味着他们无法提供适当的404服务。
但是,我宁愿返回带有404状态代码的主要404(主要用于SEO)。
用Angular处理404的最佳方法是什么? 我是否应该为此担心并坚持使用所有功能? 还是应该删除全部内容并在服务器端提供适当的404?
为了清晰而编辑
我在阅读“过滤器”部分的[AngularJS开发人员指南([https://docs.angularjs.org/guide/filter#stateful-filters)]]时遇到了“状态过滤器”。
该描述如下:
强烈建议不要编写有状态的过滤器,因为Angular无法优化它们的执行,这通常会导致性能问题。 只需将隐藏状态公开为模型并将其转换为过滤器的参数,即可将许多有状态过滤器转换为无状态过滤器。
我是Web开发的新手,所以不知道什么是有状态过滤,而Angular Documentation也没有解释:(有人可以解释一下普通过滤器和有状态过滤器之间的区别是什么吗?