【发布时间】:2014-12-19 16:53:24
【问题描述】:
所以我已经研究这个问题一周了,我似乎无法理解整个指令的内容。我已经阅读了很多帖子...
一堆视频...
并浏览了 StackOverflow 和其他论坛(链接跟随),希望有一些东西会沉入其中......我认为我遇到的问题是我想了解这些为什么/如何工作,这样我就不会被削减/将其他人的解决方案粘贴到我的代码中,但稍后又出现其他问题时不得不再次询问,因为我不知道我粘贴的代码在做什么。
然而,我发现每个人都有不同的方法给这只猫剥皮,而且似乎没有一个符合我对这应该如何工作的理解。
我正在尝试使用Metro UI CSS 库构建一个表单。我想我会从一个简单的文本框开始。是的...只是一个简单文本框。 Metro UI 文本框有一些不错的内置功能,我想保留这些功能,所以我认为这是一个很好的起点。
我读到,为了利用 AngularJS 的 Metro UI 行为,我需要将其包装在自定义指令 (Custom data-directives inside an AngularJS ng-repeat) 中。虽然这个例子并不是我想要的完全,但它似乎很容易解释我需要做什么。只需在指令的 LINK 函数中调用应用行为的函数,并将指令属性添加到输入元素...
所以我创建了一个名为“metroInputTransform”的指令并将其作为属性添加到输入元素。
<div data-ng-controller="pageOneFormCtrl as page">
<input type="text" id="txProductName"
data-ng-model="page.data.productName"
data-metro-input-transform=""
placeholder="product name" />
</div>
在指令的 LINK 函数中,我简单地调用了应用我正在寻找的行为的方法。我知道这比它需要的要冗长一些,但我正在努力学习它,所以我正在尽我所能地逐步完成它。 ...(完整代码见this fiddle)
var metroDirectives = angular.module('metroDirectives', []);
metroDirectives.directive('metroInputTransform', function ($compile) {
function postLink($scope, element, attrs, controller) {
$(element).inputTransform();
};
return {
priority: 100,
compile: function (element, attrs) {
return { postLink };
}
};
});
所以这部分奏效了。它创建了 Metro 外观和相关行为,但是...... ngModel 没有绑定到元素。所以这开始了一段漫长的旅程,通过隔离范围等概念,分解各种编译、控制器、预链接、后链接功能,至少两种不同的持久化 ngModel 的方式……所有这些都不起作用。
经过各种阅读后,我的理解是 DOM 操作应该发生在 COMPILE 函数中,以便任何 DOM 转换都可用于摘要过程的编译和链接阶段。所以我把 inputTransform() 调用移到了 COMPILE 函数... (fiddle)
return {
priority: 100,
terminal: true, // if I didn't put this everything would execute twice
compile: function (element, attrs) {
$(element).inputTransform();
return {
pre: preLink,
post: postLink
};
}
};
没有运气......同样的事情......没有绑定到 ngModel。于是我发现了“隔离作用域”的概念……
- Understanding Isolate Scope - 视频
- Using Isolate Scopes in Directives - 视频
- Using ngModel with Isolate Scope
基于此,我尝试了以下 (fiddle)...
return {
priority: 100,
scope: {
ngModel : '='
},
terminal: true, // if I didn't put this everything would execute twice
compile: function (element, attrs) {
$(element).inputTransform();
return {
pre: preLink,
post: postLink
};
}
};
没有变化……
我尝试了许多其他方法,但如果我还没有尝试过,恐怕我很快就会失去你的注意力。我得到的最接近的是 ONE-WAY 绑定,执行如下操作......即使在这里您也可以看到提取 ngModel 引用是完全不可接受的。 (fiddle)
var metroDirectives = angular.module('metroDirectives', []);
metroDirectives.directive('metroInputTransform', function () {
function postLink($scope, element, attrs, controller) {
//
// Successfully perfomes ONE-WAY binding (I need two-way) but is clearly VERY
// hard-coded. I suppose I could write a pasrsing function that would do this
// for whatever they assign to the ngModel ... but ther emust be a btter way
$(element).on("change", '[data-metro-input-transform]', function(e) {
$scope.$apply(function(){
$scope['page']['data']['productName'] = e.currentTarget.value;
});
});
};
return {
priority: 100,
terminal: true, // if I didn't put this here the compile would execute twice
compile: function (element, attrs) {
$(element).inputTransform();
return {
pre: function ($scope, element, attrs, controller, transcludeFn) { },
post: postLink
};
}
};
});
我筋疲力尽,完全不知道还有什么可以尝试的。我知道这是因为我对 AngularJS 如何/为什么以它的方式工作的无知和缺乏理解。但是我读到的每一篇文章都让我提出与已回答的问题一样多的问题,或者把我带入一个兔子洞,在这个洞里我比刚开始时更迷失。没有在现场现场研讨会上投入 3000 美元,我负担不起,在那里我可以提出我需要回答的问题,我在 Angular 上处于完全的死胡同。
如果有人能提供指导、方向......一个很好的资源......任何可以帮助特别阐明这个问题的东西,但任何可以帮助我停止旋转的东西,我将不胜感激。与此同时,我将继续阅读和重新阅读我能找到的所有内容,希望会有所突破。
谢谢
G
更新 - 2014 年 10 月 30 日
我对这个问题很感兴趣,但想坚持下去。我需要并且想要学习这个。此外,我真的想对人们为此付出的努力表示感谢,虽然他们提出了一些解决方案,这最终可能是最好的方法,但他们都回避了这个问题,即我正在尝试使用Metro UI CSS 库提供的行为。如果可能的话,我宁愿不必重写它们。
到目前为止提供的两种解决方案都消除了解决方案中的关键语句......这是行......
$(element).inputTransform()
我不想发布包含“inputTransform”定义的整个 jQuery 小部件,但我将其删减并包含在此处...
function createInputVal(element, name, buttonName) {
var wrapper = $("<div/>").addClass("input-control").addClass(name);
var button = $("<button/>").addClass(buttonName);
var clone = element.clone(true); // clone the original element
var parent = element.parent();
$(clone).appendTo(wrapper);
$(button).appendTo(wrapper);
$(wrapper).insertBefore(element);
$(element).remove(); // delete the original element
return wrapper;
};
因此,我将该指令作为属性应用,因为它背后的 Metro 代码想要克隆文本框(如果它是元素指令则不会这样做),然后删除原始输入元素。然后它创建新的 DOM 元素并将克隆的输入元素包装在新创建的 DIV 容器中。我相信,问题是......当原始元素被克隆并从 DOM 中删除时,绑定被破坏了。有意义,如果“ng-model”属性分配绑定到文本框的 reference。所以我最初的期望是,由于“ng-model”属性与元素的其余部分一起被克隆,在指令的编译事件/函数/阶段中,引用将(重新)建立到新的创建的输入元素。显然情况并非如此。您可以在这个更新的fiddle 中看到,我已经尝试将 ng-model 重新连接到新的 DOM 元素,但没有成功。
也许这是不可能的……看来重建这些东西最终可能是更容易的方法。
再次感谢 Mikko Viitalia 和 'azium' ...
【问题讨论】:
标签: javascript html angularjs angularjs-directive angularjs-scope