Angular js 从默认值初始化 ng-model
Posted
技术标签:
【中文标题】Angular js 从默认值初始化 ng-model【英文标题】:Angular js init ng-model from default values 【发布时间】:2012-11-26 00:34:01 【问题描述】:假设您有一个从数据库加载值的表单。你如何初始化 ng-model?
例子:
<input name="card[description]" ng-model="card.description" value="Visa-4242">
在我的控制器中,$scope.card 最初是未定义的。除了做这样的事情还有什么办法吗?
$scope.card =
description: $('myinput').val()
【问题讨论】:
【参考方案1】:这是新 Angular 应用程序中的常见错误。如果可以避免的话,您不想将值写入服务器上的 html。事实上,如果您可以避免让服务器完全呈现 HTML,那就更好了。
理想情况下,您希望发送您的 Angular HTML 模板,然后通过 JSON 中的 $http 提取您的值并将它们放入您的范围。
因此,如果可能,请这样做:
app.controller('MyController', function($scope, $http)
$http.get('/getCardInfo.php', function(data)
$scope.card = data;
);
);
<input type="text" ng-model="card.description" />
如果您绝对必须将您的值从您的服务器呈现到您的 HTML 中,您可以将它们放在一个全局变量中并使用 $window 访问它们:
在你的页面标题中你会写出:
<head>
<script>
window.card = description: 'foo' ;
</script>
</head>
然后在你的控制器中你会得到它:
app.controller('MyController', function($scope, $window)
$scope.card = $window.card;
);
希望对你有帮助。
【讨论】:
是的,它有帮助。我想我只是对 Angular 的人做出这个决定感到震惊。 不要感到震惊... HTML 的呈现正在从服务器转移到浏览器。如今,javascript 中有许多 MVC 框架,对于服务器来说,将 JSON/XML 数据托管到 JavaScript 应用程序比在服务器上渲染每个页面要高效得多。它抵消了客户端机器的大量工作,而不是让服务器承受打击。更不用说它节省了带宽。最重要的是,您可以拥有一个通过 HTTP 使用相同 JSON 的本机移动应用程序(或任何其他应用程序)。这就是未来。 @blesh:很好的答案。非常感谢。我同意这是前进的方向,并且我自己已经开始采用这种方法;你有任何支持这个说法的链接吗?我只是还担心将 html 的呈现从服务器移动到客户端可能会导致页面加载时间变慢,尤其是在您可以呈现大量 HTML 的移动设备中,例如导航树。 我不同意这是一个“错误”。在某些情况下,客户端渲染是最好的解决方案。在其他情况下,服务器端渲染是要走的路。您可以将 Angular 与这两种技术一起使用,并且客户端渲染不应被视为“角度方式”,因为它不是。 Angular 比这更灵活。 @blesh,当然 - 任何 SEO 很重要但爬虫替代内容的成本高于使用嵌入数据实现 angular 的成本的任何实例 - 任何高度重视感知速度的应用程序或用户体验的渲染时间 - 许多内容网站和电子商务网站都属于这些类别之一。 twitter 的工程师尝试了客户端渲染,然后又回到服务器以提供更好的用户体验,他们也概述了他们的推理:blog.twitter.com/2012/improving-performance-twittercom【参考方案2】:如果您无法按照 @blesh 的建议重新设计您的应用程序(使用 $http 或 $resource 下拉 JSON 数据并填充 $scope),您可以改用 ng-init:
<input name="card[description]" ng-model="card.description" ng-init="card.description='Visa-4242'">
另见AngularJS - Value attribute on an input text box is ignored when there is a ng-model used?
【讨论】:
+1 表示角度方式(不太受欢迎的做法)。示例:jsfiddle.net/9ymB3 我正在将 Angular 与 C# Web 表单一起使用,并且我发现在从代码隐藏/回发设置值时使用ng-init
非常有用,例如<input name="phone" data-ng-model="frm.phone" data-ng-init="frm.phone= '<%: Model.Phone %>'" data-ng-pattern="/^[0-9() \-+]+$/" type="tel" required />
。有点丑?是的,但确实可以解决这个过程中的集成难题。
+1,优雅!人们提倡快速和快速的行为,但 SO 的许多人说“全部在客户端做”,就像数以百万计的 http 调用对快速站点有好处。将数据服务器端植入模板可启用缓存策略。使用 Memcached 的静态或动态/部分。这就是推特所做的。有时它很有用,有时则没有。想强调这一点。只需要补充一点,不是你说的,@Mark。
其实我收回了,这对我来说效果最好,太棒了:***.com/a/20522955/329367
FWIW:我不喜欢模板表达式中的变量赋值,因为它不可测试。【参考方案3】:
我尝试了@Mark Rajcok 的建议。它适用于字符串值(Visa-4242)。 请参考这个fiddle。
从小提琴:
使用ng-repeat
可以完成在小提琴中完成的相同操作,每个人都可以推荐。但是在阅读了@Mark Rajcok 给出的答案后,我只是想尝试对具有配置文件数组的表单进行相同的操作。
在我拥有 $scope.profiles = [,]; 之前一切正常控制器中的代码。如果我删除此代码,我会收到错误消息。
但在正常情况下,当我从服务器打印或回显 html 时,我无法打印 $scope.profiles = [,];
。
是否有可能以与@Mark Rajcok 对<input name="card[description]" ng-model="card.description" ng-init="card.description='Visa-4242'">
等字符串值所做的类似方式执行上述操作,而无需从服务器回显JavaScript 部分。
【讨论】:
您可以使用 ng-init 初始化数组,然后使用 ng-repeat 输出表单行:jsfiddle.net/6tP6x/1【参考方案4】:这是 AngularJS 的一个明显缺乏但很容易添加的修复。只需编写一个快速指令即可从输入字段中设置模型值。
<input name="card[description]" value="Visa-4242" ng-model="card.description" ng-initial>
这是我的版本:
var app = angular.module('forms', []);
app.directive('ngInitial', function()
return
restrict: 'A',
controller: [
'$scope', '$element', '$attrs', '$parse', function($scope, $element, $attrs, $parse)
var getter, setter, val;
val = $attrs.ngInitial || $attrs.value;
getter = $parse($attrs.ngModel);
setter = getter.assign;
setter($scope, val);
]
;
);
【讨论】:
不错的快速指令。是否有充分的理由不将其打包到 ng-model 中,以便 value= 和 ng-model= 可以像大多数人所期望的那样协同工作? 相当不错!这很有用。 很好的答案!我刚刚添加了一个“修复”以使其也适用于 textareas - gist.github.com/rmontgomery429/6191275 为什么你为你的指令定义controller
,为什么不使用link
方法?我是 angularjs 的新手
需要更改为 val = $attrs.ngInitial || $attrs.value || $element.val()
才能使用选择元素。【参考方案5】:
刚刚向 Ryan Montgomery “修复”添加了对选择元素的支持
<select class="input-control" ng-model="regCompModel.numberOfEmployeeId" ng-initial>
<option value="1af38656-a752-4a98-a827-004a0767a52d"> More than 500</option>
<option value="233a2783-db42-4fdb-b191-0f97d2d9fd43"> Between 250 and 500</option>
<option value="2bab0669-550c-4555-ae9f-1fdafdb872e5"> Between 100 and 250</option>
<option value="d471e43b-196c-46e0-9b32-21e24e5469b4"> Between 50 and 100</option>
<option value="ccdad63f-69be-449f-8b2c-25f844dd19c1"> Between 20 and 50</option>
<option value="e00637a2-e3e8-4883-9e11-94e58af6e4b7" selected> Less then 20</option>
</select>
app.directive('ngInitial', function ()
return
restrict: 'A',
controller: ['$scope', '$element', '$attrs', '$parse', function ($scope, $element, $attrs, $parse)
val = $attrs.sbInitial || $attrs.value || $element.val() || $element.text()
getter = $parse($attrs.ngModel)
setter = getter.assign
setter($scope, val)
]
);
【讨论】:
【参考方案6】:恕我直言,最好的解决方案是 @Kevin Stone 指令,但我必须升级它才能在各种条件下工作(例如 select、textarea),而这个肯定可以工作:
angular.module('app').directive('ngInitial', function($parse)
return
restrict: "A",
compile: function($element, $attrs)
var initialValue = $attrs.value || $element.val();
return
pre: function($scope, $element, $attrs)
$parse($attrs.ngModel).assign($scope, initialValue);
);
【讨论】:
那么选择呢?【参考方案7】:正如其他人指出的那样,在视图上初始化数据并不是一个好习惯。 但是,建议在控制器上初始化数据。 (见http://docs.angularjs.org/guide/controller)
所以你可以写
<input name="card[description]" ng-model="card.description">
和
$scope.card = description: 'Visa-4242' ;
$http.get('/getCardInfo.php', function(data)
$scope.card = data;
);
这样视图不包含数据,并且控制器在加载实际值时初始化值。
【讨论】:
【参考方案8】:如果您喜欢 Kevin Stone 的上述方法https://***.com/a/17823590/584761 通过为特定标签(例如“输入”)编写指令来考虑一种更简单的方法。
app.directive('input', function ($parse)
return
restrict: 'E',
require: '?ngModel',
link: function (scope, element, attrs)
if (attrs.ngModel)
val = attrs.value || element.text();
$parse(attrs.ngModel).assign(scope, val);
; );
如果你走这条路,你就不必担心为每个标签添加 ng-initial。它自动将模型的值设置为标签的 value 属性。如果不设置 value 属性,它将默认为空字符串。
【讨论】:
【参考方案9】:如果你的 URL 中有 mypage/id
这样的初始化值,那么在 Angular JS 的控制器中你可以使用 location.pathname
找到 id 并将其分配给你想要的模型。
【讨论】:
【参考方案10】:这是一种以服务器为中心的方法:
<html ng-app="project">
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script>
// Create your module
var dependencies = [];
var app = angular.module('project', dependencies);
// Create a 'defaults' service
app.value("defaults", /* your server-side JSON here */);
// Create a controller that uses the service
app.controller('PageController', function(defaults, $scope)
// Populate your model with the service
$scope.card = defaults;
);
</script>
<body>
<div ng-controller="PageController">
<!-- Bind with the standard ng-model approach -->
<input type="text" ng-model="card.description">
</div>
</body>
</html>
除了$provide.value 注册了一个包含您的默认值的服务之外,它的基本思想与此问题上更流行的答案相同。
所以,在服务器上,你可以有类似的东西:
description: "Visa-4242"
并通过您选择的服务器端技术将其放入您的页面。这是一个要点:https://gist.github.com/exclsr/c8c391d16319b2d31a43
【讨论】:
据我所知,如果无法进行初始 $http 请求,这是处理问题的最 Angular 方法。如果您想稍后切换到 $http,它还有一个好处是更容易修改。一种可能的增强是返回一个承诺,而不是使转换更加容易。我会非常回避在这里设置全局变量或使用 ng-initial。【参考方案11】:您还可以在 HTML 代码中使用:
ng-init="card.description = 12345"
Angular 不建议这样做,如上所述,您应该专门使用您的控制器。
但它有效:)
【讨论】:
【参考方案12】:您可以使用自定义指令(支持 textarea、select、radio 和 checkbox),查看这篇博文 https://glaucocustodio.github.io/2014/10/20/init-ng-model-from-form-fields-attributes/。
【讨论】:
这篇文章很棒。我最喜欢的答案是因为问题是根据初始值设置输入的值。 我创建了一个 Plnkr 来测试这段代码,效果很好:plnkr.co/edit/ZTFOAc2ZGIZr6HjsB5gH?p=preview【参考方案13】:这是上述想法的更通用版本... 它只是检查模型中是否有任何值,如果没有,则将值设置给模型。
JS:
function defaultValueDirective()
return
restrict: 'A',
controller: [
'$scope', '$attrs', '$parse',
function ($scope, $attrs, $parse)
var getter = $parse($attrs.ngModel);
var setter = getter.assign;
var value = getter();
if (value === undefined || value === null)
var defaultValueGetter = $parse($attrs.defaultValue);
setter($scope, defaultValueGetter());
]
HTML(使用示例):
<select class="form-control"
ng-options="v for (i, v) in compressionMethods"
ng-model="action.parameters.Method"
default-value="'LZMA2'"></select>
【讨论】:
这对我有用,但只有在将$scope
传递给getter()
的调用之后 - 希望这可以为其他尝试这个的人解决问题!【参考方案14】:
我有一个简单的方法,因为我的表单中有一些繁重的验证和掩码。因此,我使用 jquery 再次获取我的值并将事件“更改”触发为验证:
$('#myidelement').val('123');
$('#myidelement').trigger( "change");
【讨论】:
以上是关于Angular js 从默认值初始化 ng-model的主要内容,如果未能解决你的问题,请参考以下文章
2017年前端开发Angular.JS从入门到上手企业开发视频
从 typescript angular 6 中选择默认选项值