Rxjs观察对象的更新和变化

13

我目前正在尝试观察给定对象及其所有元素的任何更改。

以下代码只在更新 object[x] 时触发,而不会在单独更新 object[x][y] 等元素时触发。

<script>
  var elem = document.getElementById("test1");

var log = function(x) {
    elem.innerHTML += x + "<br/><br/><br/>";
};

var a = [{a:1,b:2},
         {a:2,b:5}
       ];


var source = Rx.Observable
.ofObjectChanges(a)
.map(function(x) {
    return JSON.stringify(x);
});


var subscription = source.subscribe(
    function (x) {log(x);},
    function (err) {log(err);},
    function () {log('Completed');}
);

a[0] = a[1];
</script>

这段代码可以正常运行和触发。

然而,如果我改为以下方式

a[0]['a'] = 3;

那么什么也不会发生。

编辑

更好的表达方式是,我如何观察来自对象数组的变化?


1
可能首先使用ofArrayChanges - paulpdaniels
3个回答

7

如果您只希望获得嵌套对象的更改:

var source = rx.Observable.from(a).flatMap(function(item) {
  return rx.Observable.ofObjectChanges(item);
});

如果您也想像 a[0] = a[1] 这样进行更改:
var source = rx.Observable.merge(
  rx.Observable.ofArrayChanges(a),
  rx.Observable.from(a).flatMap(function(item) {
    return rx.Observable.ofObjectChanges(item);
  })
);
flatMapselectMany(它们是相同的函数)允许您遍历一个值并执行返回Observable的函数。所有这些Observables的值都被"平铺"到一个新的流中并返回。 http://reactivex.io/documentation/operators/flatmap.html

为了使其正常工作,我需要将rx更改为Rx,并在合并的末尾添加map函数。太棒了! - Antonio
14
"rx.Observable.ofObjectChanges" 已经被弃用。 - serkan
5
是的,既然这种方法已经被弃用,我真的很想看看如何在RxJS 5中观察对象的变化... - Marek M.

1
也许可以通过合并两个 Observables(一个用于数组,另一个观察数组元素)来实现类似以下的功能:
var a = [
  {a:1,b:2},
  {a:2,b:5}
];


var source1 = Rx.Observable.ofArrayChanges(a).map(function(x) {
  return JSON.stringify(x);
});

var source2 = Rx.Observable
.fromArray(a.map(function(o, i) { return [o, i]; }))
.flatMap(function(oi) {
  return Rx.Observable.ofObjectChanges(oi[0])
  .map(function(x) {
    var y = {
      type: x.type,
      object: x.object,
      name: x.name,
      oldValue: x.oldValue,
      arrayIndex: oi[1] // pass the index of the member that changed
    };
    return JSON.stringify(y);
  });
})

source = source1.merge(source2)

var subscription = source.subscribe(
  function (x) {log(x);},
  function (err) {log(err);},
  function () {log('Completed');}
);


a[0] = a[1]
a[1]['b'] = 7

感谢@electrichead,因为我们使用的是由ofObjectChangesofArrayChanges生成的源,它们从不完成,所以我们不使用concatMap

0
这是一个关于 Rx.Observable.ofNestedObjectChanges 简单实现的工作示例,你可以了解其要点并自行实现。

http://jsbin.com/wekote/edit?js,console

        Rx.Observable.ofNestedObjectChanges = function(obj) {
            if (obj == null) { throw new TypeError('object must not be null or undefined.'); }
            if (typeof Object.observe !== 'function' && typeof Object.unobserve !== 'function') { throw new TypeError('Object.observe is not supported on your platform') }
            return new Rx.AnonymousObservable(function(observer) {
                function observerFn(changes) {
                    for(var i = 0, len = changes.length; i < len; i++) {
                        observer.onNext(changes[i]);
                    }
                }
                Object.observe(obj, observerFn);
                //Recursive observers hooks - same observerFn
                traverseObjectTree(obj, observerFn);

                function traverseObjectTree(element, observerFn){
                    for(var i=0;i<Object.keys(element).length;i++){
                        var myObj = element[Object.keys(element)[i]];
                        if(typeof myObj === "object"){
                            Object.observe(myObj, observerFn);
                            traverseObjectTree(myObj,observerFn);
                        }
                    }
                }

                return function () {
                    Object.unobserve(obj, observerFn);
                };
            });
        };



        //Test
        var json = {
            element : {
                name : "Yocto",
                job : {
                    title: "Designer"
                }
            },
            element1: {
                name : "Mokto"
            }
        };

        setTimeout(function(){
            json.element.job.title = "A Great Designer";
        },3000);


        var source = Rx.Observable.ofNestedObjectChanges(json);

        var subscription = source.subscribe(
            function (x) {
                console.log(x);
            },
            function (err) {
                console.log('Error: %s', err);
            },
            function () {
                console.log('Completed');
            });

        json.element.name = "Candy Joe";

在Safari和Chrome中检查过了,提供的链接代码片段似乎有问题。 - akaRem

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接