我正在为遗留系统实现Web界面,因此来自服务器的数据是固定的。该服务器数据指定要向用户显示的各种控件,例如,组合框,按钮等我已经解析了服务器数据,并通过$ sce.trustAsHtml()为控件添加了HTML。
问题是控件未绑定到模型。如果我输入ng-change事件处理程序,则不会使用用户编辑调用它。
我读了这篇有用的帖子:call function inside $sce.trustAsHtml() string in Angular js表示:
ng-bind-html只会插入普通的旧HTML和 不打扰编译它(所以任何指令 html不会被angular处理。
所以这似乎是我的问题。但我不太了解Angular,以便理解上述帖子提供的解决方案。
我在以下HTML中显示动态文本
<span ng-repeat="i in range(0, item.Data.DisplayText.JSArray.length-1)">
<span ng-bind-html="item.Data.DisplayText.JSArray[i] | trusted_html"></span>
<span ng-show="!$last"><br></span>
</span>
以下是range()的定义:
$scope.range = function(min, max){
var input = [];
for (var i=min; i<=max; i++) input.push(i);
return input;
};
以下是过滤器的定义:
app.filter('trusted_html', ['$sce', function($sce){
return function(text) {
return $sce.trustAsHtml(text);
};
}]);
我已经帮助设置了部分内容,并在堆栈溢出时从这里收集了解决方案。我很抱歉无法提供这些原始解决方案的链接。
我认为我需要做的是扩展我的trusted_html过滤器,以便$ $编译文本。但我不知道是否会编译整个DOM(可能很慢)或只是文本参数。
任何帮助将不胜感激。
附录:
我很欣赏@Simeon Cheeseman的回应。他表示,如我最初想要的那样,指令会比过滤器更好。我一直在研究文档和阅读帖子,看起来他是100%正确的。 DOM操作应该在指令中进行。但是,我不喜欢有一个指令(例如上面链接中的示例中的'compile-template')修复另一个指令(ng-bind-html)的缺点。这对我来说似乎很糟糕。我如何知道ng-bind-html指令将在compile-template指令之前执行?如果执行顺序被颠倒会发生什么?
所以我将考虑是否可以将它们组合成一个函数。我会在下面大声思考。如果有人发现问题,请告诉我。
首先,我查看了angular.js中的ng-bind-html指令:https://code.angularjs.org/1.2.9/angular.js,在此文件中,我搜索了'ngBindHTML'。
var ngBindHtmlDirective = ['$sce', '$parse', function($sce, $parse) {
return function(scope, element, attr) {
element.addClass('ng-binding').data('$binding', attr.ngBindHtml);
var parsed = $parse(attr.ngBindHtml);
function getStringValue() { return (parsed(scope) || '').toString(); }
scope.$watch(getStringValue, function ngBindHtmlWatchAction(value) {
element.html($sce.getTrustedHtml(parsed(scope)) || '');
});
};
}];
以上不是app.directive()的形式,也不会返回{link:fun()}对象。所以我不确定这是否直接适用于与下面的compile-template指令进行比较。但是,我确实在2025行找到了以下内容。所以我认为我走的是正确的道路:
ngBindHtml: ngBindHtmlDirective,
所以这个ngBindHtmlDirective以某种方式充当ngBindHtml。
我将挑选上面的代码,并对其进行改革。而且,仅供参考,我对javascript相对较新,匿名函数和闭包对我来说仍然有点新鲜。所以我试图删除匿名函数以便我清楚。我将添加一些评论,这些评论来自我在Angular的网站上提到的信息等。
var DirectiveFnFactory = function($sce, $parse) {
var DirectiveHandlerFn = function(scope, element, attr) {
//Input: scope = an Angular scope object
// element = the jqLite-wrapped element that this directive matches
// attr = a hash object with key-value pairs of normalized attribute
// names and their corresponding attribute values
//closure scope input: $compile object
// $parse object
//Result: none
element.addClass('ng-binding');
// .addClass is jQuery: http://api.jquery.com/addclass/
// adds class to element
element.data('$binding', attr.ngBindHtml);
// adds value to key of '$binding';
var parsed = $parse(attr.ngBindHtml);
//Input: attr.ngBindHtml should be the HTML to be bound.
//Result: $parse() returns a function which represents the
// compiled input expression.
// This function will have this signature:
// function(context, locals)
// context – {object} – an object against which any expressions
// embedded in the strings are evaluated against
// (typically a scope object).
// locals – {object=} – local variables context object, useful for
// overriding values in context.
// The returned function also has the following properties:
// literal – {boolean} – whether the expression's top-level node is a
// JavaScript literal.
// constant – {boolean} – whether the expression is made
// entirely of JavaScript constant literals.
// assign – {?function(context, value)} – if the expression is assignable,
// this will be set to a function to change its value
// on the given context.
function getStringValue() { return (parsed(scope) || '').toString(); }
//First, this is executing the function that was returned by parsed(),
// passing scope that was given to DirectiveHandlerFn()
//Next converting Fn() output to string.
//In the case of binding HTML. I would think that the output of this would be HTML
var watchListener = function ngBindHtmlWatchAction(value) {
element.html($sce.getTrustedHtml(parsed(scope)) || '');
//.html is jquery: http://api.jquery.com/html/
// Get the HTML contents of the first element in the set of matched elements
// or set the HTML contents of every matched element.
}
scope.$watch(getStringValue, watchListener);
//$watch signature:
// $watch(watchExpression, listener, [objectEquality]);
// This registers a listener callback to be executed whenever the
// watchExpression() changes
// The listener() has this signature (determined by example, not API documents!):
// listener(newValue, oldValue);
// The listener is called automagically by Angular when the value changes.
}
return DirectiveHandlerFn;
}
var ngBindHtmlDirective = ['$sce', '$parse', DirectiveFnFactory];
好的,现在我将首先引用compileTemplate指令,(从这里:call function inside $sce.trustAsHtml() string in Angular js):
.directive('compileTemplate', function($compile, $parse){
return {
link: function(scope, element, attar){
var parsed = $parse(attr.ngBindHtml);
function getStringValue() { return (parsed(scope) || '').toString(); }
//Recompile if the template changes
scope.$watch(getStringValue, function() {
$compile(element, null, -9999)(scope);
//The -9999 makes it skip directives so that we
//do not recompile ourselves
});
}
}
});
然后选择它以允许评论:
var DirectiveObjFactory = function($compile, $parse){
//input: $compile object
// $parse object
var DirectiveHandlerFn = function(scope, element, attr) {
//Input: scope = an Angular scope object
// element = the jqLite-wrapped element that this directive matches
// attr = a hash object with key-value pairs of normalized attribute
// names and their corresponding attribute values
//closure scope vars: $compile object
// $parse object
//Result: none
var parsed = $parse(attr.ngBindHtml);
//Input: attr.ngBindHtml should be the HTML to be bound.
//Result: $parse() returns a function which represents the
// compiled input expression.
// This resulted function will have this signature:
// function(context, locals)
// context – {object} – an object against which any expressions
// embedded in the strings are evaluated against
// (typically a scope object).
// locals – {object=} – local variables context object, useful for
// overriding values in context.
// The returned function also has the following properties:
// literal – {boolean} – whether the expression's top-level node is a
// JavaScript literal.
// constant – {boolean} – whether the expression is made
// entirely of JavaScript constant literals.
// assign – {?function(context, value)} – if the expr is assignable,
// this will be set to a function to change its value
// on the given context.
function getStringValue() { return (parsed(scope) || '').toString(); }
//First, this is executing the function that was returned by parsed(),
// passing scope that was given to DirectiveHandlerFn()
//Next converting Fn() output to string.
//In the case of binding HTML. I would think that the output of this
// would be HTML
var watchListener = function ngBindHtmlWatchAction(value) {
//Input: value -- actual the newValue. (oldValue not accepted here)
//Locally scoped vars used -- element, scope
// -- Adding Below is from ngbindHtml ------------
element.html($sce.getTrustedHtml(parsed(scope)) || '');
//.html is jquery: http://api.jquery.com/html/
//Gets the HTML contents of the first element in the set of matched
// elements or set the HTML contents of every matched element.
// -- End addition ------------
var compFn = $compile(element, null, -9999);
//NOTE: I can't find formal documentation for the parameters for $compile()
// below is from examples found...
//Input: element -- the HTML element to compile
// transcludeFunction -- null here.
// maxPriority -- "The -9999 makes it skip directives so that we
// do not recompile ourselves"
//$compile() compiles an HTML string or DOM into a template and
// produces a template function, which can then be used to link scope
// and the template together.
// The returned function accepts a scope variable, against which the code
// is evaluated.
compFn(scope); // execute the returned function, passing scope
} // end watchListener
scope.$watch(getStringValue, watchListener);
//$watch() function signature:
// $watch(watchExpression, listener, [objectEquality]);
// This registers a listener callback to be executed whenever the
// watchExpression changes
// The supplied listener() should have this signature:
// listener(newValue, oldValue);
// The listener is called automagically by Angular when the value changes.
} // end DirectiveHandlerFn
return {link: DirectiveHandlerFn}
} // end DirectiveObjFactory
app.directive('compileTemplate', DirectiveObjFactory);
我想我差不多了。让我试着把这一切都重新组合起来......
.directive('bindAndWatchHtml', ['$sce', function($compile, $parse){
return {
link: function(scope, element, attr){
var parsed = $parse(attr.ngBindHtml);
function getStringValue() { return (parsed(scope) || '').toString(); }
//Recompile if the template changes
scope.$watch(getStringValue, function() {
element.html($sce.getTrustedHtml(parsed(scope)) || '');
$compile(element, null, -9999)(scope);
//The -9999 makes it skip directives so that we do not recompile ourselves
});
}
}
}]);
希望这将绑定并编译html,并同时信任HTML。
现在进行测试......
附录:
不起作用..在线:
element.html($sce.getTrustedHtml(parsed(scope)) || '');
它抱怨$ sce没有定义。
...
我更改了以下行,并允许定义$ sce。
app.directive('bindAndWatchTrustedHtml0', ['$compile', '$parse', '$sce',
function($compile, $parse, $sce){ ...
接下来,我在尝试在不安全的位置使用安全文本时收到错误....
...
这只是花了太长时间。我放弃了这个。我使用了这个,根据最顶层的原始链接,它可以工作。
<span ng-bind-html="item.Data.DisplayText.JSArray[i] | trusted_html" compile-template>
</span>
答案 0 :(得分:1)
请参阅https://code.angularjs.org/1.2.19/docs/api/ng/service/ $ compile以了解如何编译。
基本上你打电话给compiledHtml = $compile('<div>' + text + '</div>')($scope).html()
。
我认为你创建一个指令比使用过滤器更好,因为你需要编译$scope
变量。
也许您可以使用ngBindTemplate或ngInclude