GVKun编程网logo

angularjs – 当模型改变时,如何绑定一次方式角度和绑定?(angularjs数据绑定)

22

对于angularjs–当模型改变时,如何绑定一次方式角度和绑定?感兴趣的读者,本文将会是一篇不错的选择,我们将详细介绍angularjs数据绑定,并为您提供关于AngularJS_AngularJs

对于angularjs – 当模型改变时,如何绑定一次方式角度和绑定?感兴趣的读者,本文将会是一篇不错的选择,我们将详细介绍angularjs数据绑定,并为您提供关于AngularJS _AngularJs 双向绑定原理(数据绑定机制)、angularjs – Angular JS 1.3 ng-bind的一次性绑定,具有三元条件、angularjs – Angular JS MVC Web API模型/参数不绑定.NET Core、angularjs – Angular JS:如何绑定promises的有用信息。

本文目录一览:

angularjs – 当模型改变时,如何绑定一次方式角度和绑定?(angularjs数据绑定)

angularjs – 当模型改变时,如何绑定一次方式角度和绑定?(angularjs数据绑定)

有任何解决方案或角度插件可以单向绑定并在模型更改时再次绑定吗?
现在我正在使用插件 bind-once,但它只是第一次绑定然后它破坏观察者.例:

<div bindonce="model"><span bo-bind="model.title"></span></div>

解决方法

Angular已经为你做了这件事

<div><span ng-bind="model.title"></span></div>

要么

<div><span>{{model.title}}</span></div>

AngularJS _AngularJs 双向绑定原理(数据绑定机制)

AngularJS _AngularJs 双向绑定原理(数据绑定机制)

原文地址:

https://www.jianshu.com/p/ad0c48810bf1

 

AngularJsscope 模型上设置了一个 监听队列,用来监听数据变化并更新 view 。每次绑定一个东西到 view(html) 上时 AngularJs 就会往 $watch 队列里插入一条 $watch,用来检测它监视的 model 里是否有变化的东西。当浏览器接收到可以被 angular context 处理的事件时,$digest 循环就会触发。$digest 会遍历所有的 $watch。从而更新DOM

$watch

这有点类似于我们的观察者模式,在当前作用域$scope下,我们创建一个监控器$watchers和一个监听器$watch$watchers 负责管理所有的 $watch,当我们每次绑定到UI上的时候就自动创建一个$watch,并把它放到 $watchers

controller.js

app.controller('MainCtrl', function($scope) {
  • $scope.Hello = "Hello";
  • $scope.world = "World";
  • });

    index.html

    1. <div>{{Hello}}</div>

    这里,即便我们在$scope上添加了两个变量,但是只有一个绑定在了UI上,因此在这里只生成了一个$watch

    $digest

    当浏览器接收到可以被angular context处理的事件时,$digest循环就会触发。$digest将会遍历我们的$watch,如果$watch没有变化,这个循环检测就将停止,如果有至少一个更新过,这个循环就会再次触发,直到所有的$watch都没有变化。这样就能够保证每个model都已经不会再变化。这就是脏检查(Dirty Checking)机制

    controller.js

    1. app.controller('MainCtrl', function() {
    2. $scope.name = "Foo";
    3. $scope.changeFoo = function() {
    4. $scope.name = "Bar";
    5. }
    6. });

    index.js

    1. <div>{{ name }}</div>
    2. <button ng-click="changeFoo()">Change the name</button>
    • 当我们按下按钮
    • 浏览器接收到一个事件,进入angular context
    • $digest循环开始执行,查询每个$watch是否变化。
    • 由于监视$scope.name$watch报告了变化,它会强制再执行一次$digest循环。
    • 新的$digest循环没有检测到变化。
    • 更新与$scope.name新值相应部分的DOM

    $apply

    $apply 我们可以直接理解为刷新UI。如果当事件触发时,你调用$apply,它会进入angular context,如果没有调用就不会进入,之后的$digest检测机制就不会触发

    1. app.directive('clickable', function() {
    2. return {
    3. restrict: "E",
    4. scope: {
    5. foo: '='
    6. },
    7. template: '<ul><li>{{foo}}</li></ul>',
    8. link: function(scope, element, attrs) {
    9. element.bind('click', function() {
    10. scope.foo++;
    11. console.log(scope.foo);
    12. });
    13. }
    14. }
    15. });

    当我们调用clickable指令的时候,我们可以看到foo的值增加了,但是界面上显示的内容并没有改变。$digest脏检测机制没有触发,检测foo$watch就没有执行。

    $apply()方法的两种形式

    1) 无参

    $scope.$apply();

     

    1. element.bind('click', function() {
    2. scope.foo++;
    3. //if error
    4. scope.$apply();
    5. });

    当我们使用这种形式的时候,如果在scope.$apply之前程序发生异常,那scope.$apply没有执行,界面就不会更新

    2) 有参

    1. $scope.$apply(function(){
    2. ...
    3. })

     

    1. element.bind('click', function() {
    2. scope.$apply(function() {
    3. scope.foo++;
    4. });
    5. })

    如果用这种形式,即使后面的发生异常,数据还是会更新。

    在 AngularJS 中使用 $watch

    常用的使用方式:

    1. $scope.name = 'Hello';
    2. $scope.$watch('name', function(newValue, oldValue) {
    3. if (newValue === oldValue) { return; }
    4. $scope.updated++;
    5. });

    传入到$watch()中的第二个参数是一个回调函数,该函数在name的值发生变化的时候会被调用。

    如果要监听的是一个对象,那还需要第三个参数:

    1. $scope.data.name = 'Hello';
    2. $scope.$watch('data', function(newValue, oldValue) {
    3. if (newValue === oldValue) { return; }
    4. $scope.updated++;
    5. }, true);

    表示比较的是对象的值而不是引用,如果不加第三个参数true,在 data.name 变化时,不会触发相应操作,因为引用的是同一引用。

    总结

    1) 只有在$scope变量绑定到页面上,才会创建 $watch

    2) $apply决定事件是否可以进入angular context

    3) $digest 循环检查model时最少两次,最多10次(多于10次抛出异常,防止无限检查)

    4) AngularJs自带的指令已经实现了$apply,所以不需要我们额外的编写

    5) 在自定义指令时,建议使用带function参数的$apply



    作者:Nickyzhang
    链接:https://www.jianshu.com/p/ad0c48810bf1
    來源:简书
    简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

    angularjs – Angular JS 1.3 ng-bind的一次性绑定,具有三元条件

    angularjs – Angular JS 1.3 ng-bind的一次性绑定,具有三元条件

    如果我需要在data-ng-bind指令内对三元条件使用一次时间绑定,这是否正确?

    <span data-ng-bind="::model.boolean ? 'json.item.value1' : 'json.item.value2'"></span>

    要么

    <span data-ng-bind="::(model.boolean ? 'json.item.value1' : 'json.item.value2')"></span>

    解决方法

    是.整个表达式,无论它是什么,都将被解析并读取一次.

    内部会发生什么相当于:

    // If not bound
    value = $parse("model.boolean ? 'json.item.value1' : 'json.item.value2'")(scope)

    注意:如果model.boolean为true,您实际上会看到字符串“json.item.value1”而不是它包含的实际值.如果你想评估它,你需要删除单引号’所以它变成:

    <span data-ng-bind="::model.boolean ? json.item.value1 : json.item.value2"></span>

    angularjs – Angular JS MVC Web API模型/参数不绑定.NET Core

    angularjs – Angular JS MVC Web API模型/参数不绑定.NET Core

    我正在使用带有TypeScript和ASP.NET Core MVC / API的Angular JS.

    我有一个apiService来处理对服务器的所有POST和GET请求,如下所示:

    module TBApp {
    
        export class apiService {
    
            static $inject = ['$http','notificationService'];
    
            constructor(private $http,private notificationService: notificationService) {
    
            }
    
            get(url,config,success,failure) {
    
                return this.$http.get(url,config)
    
                    .then(result => { this.handleResponse(result,success); },result => { this.handleError(result,failure) });
            }
    
            post(url,data,failure) {
    
                return this.$http.post(url,data)
                    .then(result => { this.handleResponse(result,failure) });
            }
    
            handleResponse(result,success) {
    
                alert('success');
                success(result);
    
            }
    
            handleError(result,failure) {
    
                if (result.status === '401') {
    
                    this.notificationService.displayError('Authentication required.');
                    //this.$rootScope.prevIoUsstate = this.$location.path();
                    //this.$location.path('/login');
    
                }
                else if (failure !== null) {
                    failure(result);
                }
            }
        }
    }

    现在,当我发送此请求时:

    onCompanyChanged(selectedCompany,model,companyName) {
    
            this.apiService.post('/api/Dashboard/GetAssetListByCompany',{ companyId: selectedCompany.id },response => {
    
                    this.assetListviewmodel = response.data.data;
    
    
                },response => {
                this.notificationService.displayError(response.data.message);
            });
        }

    它没有绑定控制器中的companyId

    这是控制器:

    [Route("api/[controller]")]
        public class DashboardController : BaseController
        {
            [HttpPost]
            [Route("GetAssetListByCompany")]
            public IActionResult GetAssetListByCompany([FromBody]int companyId)
            {
                return CreateJsonResult(() =>
                {
                    if (companyId == 0) { return new xPTJsonResult(null,xPTStatusCodesEnum.Success,"Company Id is 0"); }
    
                   //var treeModel = _dashboardProvider.GetTreeModelByCompany(companyId,usermodel);
    
                    return new xPTJsonResult(null,"Loaded assets successfully");
    
                });
            }
    
    }

    即使我在浏览器中检查了请求,也表明companyId在Payload中.

    enter image description here

    NOTE: The same function works when I post a viewmodel

    编辑

    在上面的场景中,我只将一个参数传递给控制器​​,但在某些情况下,我希望能够在不使用viewmodel的情况下传递2或3个参数.

    例如

    public IActionResult GetAssetListByCompany([FromBody]int companyId,[FromBody]int assetId)
    {....

    要么

    public IActionResult GetAssetListByCompany([FromBody]int companyId,[FromBody]int assetId,[FromBody]bool canEdit = false)
        {.....

    然后在客户端我可以这样做:

    this.apiService.post('/api/Dashboard/GetAssetListByCompany',{ companyId: selectedCompany.id,assetId: 123 }.....

    要么

    this.apiService.post('/api/Dashboard/GetAssetListByCompany',canEdit: true,assetId: 22 }....

    解决方法

    这里最好的方法是遵循HTTP准则并将操作从POST更改为GET,因为您不修改任何数据.这很简单,仍然可以使用URI通过您的请求发送数据.

    MVC改变了

    有关各种选项,请参阅Model Binding,此处的最佳方法是基于查询字符串进行绑定,因为您只需要一个基本类型.如果您有一个基本类型数组仍然可以绑定到查询字符串,则查询字符串变量名称将为每个值重复一次.

    因此,我们所做的唯一更改是指定参数来自查询字符串,并且它与Http Get请求而不是Post相关联.

    [Route("api/[controller]")]
    public class DashboardController : BaseController
    {
        [HttpGet] // change to HttpGet
        [Route("GetAssetListByCompany")]
        public IActionResult GetAssetListByCompany([FromQuery]int companyId) // use FromQuery
        {
            return CreateJsonResult(() =>
            {
                if (companyId == 0) { return new xPTJsonResult(null,"Company Id is 0"); }
    
               //var treeModel = _dashboardProvider.GetTreeModelByCompany(companyId,usermodel);
    
                return new xPTJsonResult(null,"Loaded assets successfully");
    
            });
        }
    }

    AngularJS发生了变化

    我们扩展apiService以允许使用HttpGet传递调用数据.这可以使用params on the $http call完成,它将使用名称作为查询字符串值名称和值作为值部分,根据传入的数据动态创建URL.

    export class apiService {
        /* all other code is left as is,just change the get method to also accept data via the params. If null is passed in then it is ignored. */
        get(url,failure) {
            return this.$http({
                url: url,config: config,params: data,method: "GET"
                })
                .then(result => { this.handleResponse(result,failure) });
        }
    }

    在通话中我们只需要从post更改为get,它应该可以工作.

    // only change from post to get
    onCompanyChanged(selectedCompany,companyName) {
        this.apiService.get('/api/Dashboard/GetAssetListByCompany',response => {
                this.assetListviewmodel = response.data.data;
            },response => {
            this.notificationService.displayError(response.data.message);
        });
    }

    编辑 – 这很灵活

    更重要的是,这种设计在角度方面是灵活的.如果您扩展MVC操作或具有采取其他参数的各种操作,则无需执行任何其他更改即可运行.例:

    [HttpGet]
    [Route("GetSomethingElseFromServer")]
    public IActionResult GetSomethingElseFromServer([FromQuery]int companyId,[FromQuery]string assetName,[FromQuery]string companyModelNumber) // use FromQuery

    对你的角度api的调用将是

    this.apiService.get('/api/Dashboard/GetSomethingElseFromServer',{ companyId: companyId,assetName: somePassedInAssetNameVar,companyModelNumber: somePassedInModelNumber }

    编辑 – 您也可以发送数组

    要回答关于如何将多个基元类型作为数组发送的问题,您可以这样做.同样,这假设它不是您要发送的复杂类型,但是,例如,公司ID列表.

    c#代码

    [HttpGet]
    [Route("GetAssetListByCompany")]
    public IActionResult GetAssetListByCompany([FromQuery]int[] companyIds) // use an array of int ie. int[]. i changed the variable name to make it clear there can be more than 1

    Angular调用,注意没有必要更改服务

    onCompanyChanged(selectedCompany,{ "companyIds[]": [id1,id2,id3] },// note the name is Now enclosed in quotes,made plural,and includes []. The value is an array
            response => {
                this.assetListviewmodel = response.data.data;
            },response => {
            this.notificationService.displayError(response.data.message);
        });
    }

    编辑 – 如果你想要POST

    您目前只发送一个原始字段,因此POST中的MVC框架无法正确反序列化.您需要将参数包装在视图模型中,将其作为查询字符串部分发送,或将其作为表单字段值发送.这是带有查询字符串部分的POST,它可以正常工作.

    选项1

    将其附加到URL

    [HttpPost] // change to HttpGet
    [Route("GetAssetListByCompany")]
    public IActionResult GetAssetListByCompany([FromQuery] int companyId) // use FromQuery

    角度呼叫

    this.apiService.post('/api/Dashboard/GetAssetListByCompany/?companyId=' + selectedCompany.id +,null,// the rest of the code remains unchanged so I did not include it

    选项2

    扩展apiService以获取params对象,以便它可以构建您的查询.无论哪种方式,你都会遇到调用者不得不对http调用有所了解.

    this.apiService.post('/api/Dashboard/GetAssetListByCompany',{companyId: selectedCompany.id},// the rest of the code remains unchanged so I did not include it
    
    post(url,params,failure) {
        return this.$http({
            url: url,data: data,params: params,method: "POST"
            })
            .then(result => { this.handleResponse(result,failure) });
    }

    选项3

    更新视图模型以采用复杂类型,这不需要更改角度代码.

    public class ListByCompanyModel {
        public int CompanyId {get;set;}
    }
    
    [HttpPost] // change to HttpGet
    [Route("GetAssetListByCompany")]
    public IActionResult GetAssetListByCompany([FromBody] ListByCompanyModel model) // use FromQuery

    angularjs – Angular JS:如何绑定promises

    angularjs – Angular JS:如何绑定promises

    我试图绑定一个视图的承诺。我不知道你是否可以直接做到这一点,但这是我试图做的。任何想法我做错了什么?

    注意:源是有点设计的超时和使用静态数据,但这是为了使代码更容易诊断。

    编辑:JSfiddle页面:http://jsfiddle.net/YQwaf/27/

    编辑:解决方案:原来,你可以直接绑定承诺。我有我的原始代码的两个问题:

    >使用setTimeout()而不是angular的$ timeout是一个问题。 Angular不知道它需要刷新UI超时时触发(你可以使用$ scope解决这个问题。$ apply在setTimeout,或者你可以使用$ timeout)
    >绑定到返回promise的函数是一个问题。如果它第二次被调用,它做出另一个承诺。更好的是将范围变量设置为promise,并且只根据需要创建一个新的promise。 (在我的case,这是调用$ scope。$ watch在国家代码)

    HTML:

    <div ng:controller="addressValidationController">
        Region Code <select ng:model="regionCode" ng:options="r.code as r.name for r in getRegions()"/>
        Country Code<select ng:model="countryCode"><option value="US">United States</option><option value="CA">Canada</option></select>
    </div>

    JS:

    function addressValidationController($scope,$q) {
        var regions = {
            US: [{code: 'WI',name: 'Wisconsin'},{code: 'MN',name: 'Minnesota'}],CA: [{code: 'ON',name: 'Ontario'}]
        };
        $scope.getRegions = function () {
            var deferred = $q.defer();
            setTimeout(function () {
                var countryRegions = regions[$scope.countryCode];
                console.log(countryRegions);
                if(countryRegions === undefined) {
                    deferred.resolve([]);
                } else {
                    deferred.resolve(countryRegions);
                }
            },1000);
            return deferred.promise;
        };
    }

    WARNING: this answer was accurate when it was written,but as of 1.2 the Angular template engine does not handle promises transparently! — @Malvolio

    是的模板引擎(和表达式)处理承诺透明,但我会分配promise到控制器中的scope属性,而不是每次调用一个函数返回一个新的promise(我认为这是你的问题,解决promise丢失,因为一个新的promise每次都返回)。

    JSfiddle:http://jsfiddle.net/YQwaf/36/

    HTML:

    <div ng:controller="addressValidationController">
        Region Code <select ng:model="regionCode" ng:options="r.code as r.name for r in regions"/>
        Country Code<select ng:model="countryCode"><option value="US">United States</option><option value="CA">Canada</option></select>
    </div>

    JS:

    function addressValidationController($scope,$q,$timeout) {
        var regions = {
            US: [{
                code: 'WI',{
                code: 'MN',CA: [{
                code: 'ON',name: 'Ontario'}]
        };
    
        function getRegions(countryCode) {
            console.log('getRegions: ' + countryCode);
            var deferred = $q.defer();
            $timeout(function() {
                var countryRegions = regions[countryCode];
                if (countryRegions === undefined) {
                    console.log('resolve empty');
                    deferred.resolve([]);
                } else {
                    console.log('resolve');
                    deferred.resolve(countryRegions);
                }
            },1000);
            return deferred.promise;
        };
    
        $scope.regions = [];
    
        // Manage country changes:
        $scope.$watch('countryCode',function(countryCode) {
            if (angular.isDefined(countryCode)) {
                $scope.regions = getRegions(countryCode);
            }
            else {
                $scope.regions = [];
            }
        });
    }​

    我们今天的关于angularjs – 当模型改变时,如何绑定一次方式角度和绑定?angularjs数据绑定的分享已经告一段落,感谢您的关注,如果您想了解更多关于AngularJS _AngularJs 双向绑定原理(数据绑定机制)、angularjs – Angular JS 1.3 ng-bind的一次性绑定,具有三元条件、angularjs – Angular JS MVC Web API模型/参数不绑定.NET Core、angularjs – Angular JS:如何绑定promises的相关信息,请在本站查询。

    本文标签: