评级系统 javascript 不会将结果发送到 firebase

Rating system javascript will not send results to firebase

我有一个可以正常运行的脚本,可以根据评分值推送评分,例如 1/5、2/5、3/5 等。但该脚本根本不与 firebase 通信。我的 javascript 是否有问题,这会阻止输入值按指示发送到 firebase?这是所有必要的代码。另外,在文档的头部有一个 link 到 firebase.js。

(function() {
    var firebaseUrl = "https://myFirebase.firebaseIO.com/rating";
    var itemId = (rootRef).child;
    var rootRef = new Firebase(firebaseUrl);  // Reference the Firebase location
    var itemRef = rootRef.child("items").child(itemId);     //Define itemRef as the variable for itemId in firebase
    var star = $('.rating');
    var numRatings;
        star.click(function() {     //Watch out for rating1 inside of the website and grab its value. i.e. 1, 2, 3, 4, or 5
            itemRef.child("ratings").child("numRatings").set(star.val());   //Set ratings inside of Firebase with values such as 1, 2, 3, 4, and 5, under items such as item1, item2, item3, etc... 
        });

    var cumulativeRating;
    var averageRating;
    itemRef.child("ratings").on("value", function(ratingsSnapshot) {
        var ratingsData = ratingsSnapshot.val();
        numRatings = ratingsData.numRatings;
        cumulativeRating = ratingsData.cumulativeRating;
        averageRating = cumulativeRating / numRatings;
    });
})();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!--Rating system begin-->
    <div class="rating">
        <div class="starRating">
            <div>
                <div>
                    <div>
                        <div>
                        <input id="rating1" class="rating" type="radio" name="rating" value="1">
                        <label for="rating1"><span>1</span></label>
                        </div>
                    <input id="rating2" class="rating" type="radio" name="rating" value="2">
                    <label for="rating2"><span>2</span></label>
                    </div>
                <input id="rating3" class="rating" type="radio" name="rating" value="3">
                <label for="rating3"><span>3</span></label>
                </div>
            <input id="rating4" class="rating" type="radio" name="rating" value="4">
            <label for="rating4"><span>4</span></label>
            </div>
        <input id="rating5" class="rating" type="radio" name="rating" value="5">
        <label for="rating5"><span>5</span></label>
        </div>
                <h3 class="ratingtext">Rated 4/5 by 103 users</h3>   
                <!--Rating system end-->

您更新安全规则了吗?

在 firebase 中(link 参考)转到规则并添加感兴趣的数组或对象(从教程中复制示例对象)

例如设置rating的读写为true

你的代码中有不少小错误。我将带您了解其中的一些。但请不要只是复制代码,而是花时间了解我是如何解决这些问题的。您的首要目标应该是能够调试自己的代码以摆脱这些更简单的错误。

OK,我把两个问题写上去。可能还有更多,但这已经需要足够的时间了。

  1. 处理 Firebase 中还没有数据的情况
  2. 获取点击的单选按钮的值

处理 Firebase 中还没有数据的情况

当我将您的代码粘贴到 jsbin 时发生的第一件事是它会将此记录到开发工具中的 JavaScript 控制台(您可以使用 F12开发时应该始终保持打开状态):

Uncaught TypeError: Cannot read property 'numRatings' of null

这是空指针异常的现代 JavaScript 版本,是因为您在 nullundefined 上执行了 .numRatings。幸运的是,你只有一个地方 .numRatings

itemRef.child("ratings").on("value", function(ratingsSnapshot) {
    var ratingsData = ratingsSnapshot.val();
    numRatings = ratingsData.numRatings;
    cumulativeRating = ratingsData.cumulativeRating;
    averageRating = cumulativeRating / numRatings;
});

所以看起来 ratingsData 没有价值,这确实发生在项目第一次获得评级时。在这种情况下,Firebase 将使用 null(或 undefined)触发 value 事件。

处理起来很容易:

itemRef.child("ratings").on("value", function(ratingsSnapshot) {
    var ratingsData = ratingsSnapshot.val();
    if (ratingsData) {
        numRatings = ratingsData.numRatings;
        cumulativeRating = ratingsData.cumulativeRating;
        averageRating = cumulativeRating / numRatings;
    }
});

在实际实施中,您可能希望向 if 添加一个 else 并表明还有 no/not 足够的评级。

获取单击的单选按钮的值

将点击值传递给 Firebase 的代码段是:

var star = $('.rating');
star.click(function() {
    itemRef.child("ratings").child("numRatings").set(star.val());
});

我做的第一件事是在其中添加一个日志语句,以查看点击是否通过代码:

var star = $('.rating');
star.click(function() {
    console.log('click');
    itemRef.child("ratings").child("numRatings").set(star.val());
});

当我现在单击单选按钮时,它会记录 click。所以看起来连接正确。我通常会在下一步放置 JavaScript debugger statement 而不是 console.log,但这次决定不这样做。

我做的下一个技巧是设置一个简单的 Firebase 记录器来显示更改是否通过到 Firebase:

 new Firebase('https://you.firebaseIO.com/rating').on('value', function(s) { console.log(JSON.stringify(s.val())); })

您可以将其添加到脚本顶层的任何位置。我最常将它添加到 Chrome 的开发工具的控制台中。每次 Firebase 的值发生变化时,它都会记录如下内容:

{"items":{"42":{"ratings":{"numRatings":"3"}}}}

或者这是它应该做的,但在您的原始脚本中它从来没有这样做过。所以我们进入了点击处理程序,但该值没有进入 Firebase。

仔细检查发现了一些奇怪的东西:

var star = $('.rating');
star.click(function() {
    itemRef.child("ratings").child("numRatings").set(star.val());
});

您在此代码段的第一行中使用变量 star 来指向所有评级元素。但随后在点击处理程序中您执行 star.val(),这意味着您希望它引用单个评级元素:被点击的元素。

此处关于变量名称的快速说明:您通过对包含所有评级元素的变量使用单数 star 为自己设置了这个错误。我将该变量命名为 stars,以表明它包含多颗星。这样,当您键入 stars.val().

时,您会更容易看到某些东西有气味

我不是 jQuery 专家,但是 docs for jQuery's click method 的快速 Google 似乎表明您可以作为 this 访问单击的元素。所以片段需要是:

var star = $('.rating');
star.click(function() {
    itemRef.child("ratings").child("numRatings").set($this).val());
});

然后,我的 Firebase JSON 记录器开始输出数据:

{"items":{"42":{"ratings":{"numRatings":"3"}}}}

这些值现在已进入 Firebase!

从问题中消除技术

请注意,最后一项更改与 Firebase 无关。如果您尝试提醒值,也会发生这种情况:

var star = $('.rating');
star.click(function() {
    alert(star.val());
});

这是调试问题(或创建 MCVE)时的一个关键点:尝试尽可能多地从问题中删除技术。通过从这个小代码片段中删除 Firebase,问题从 "why doesn't my star rating make it into Firebase?" 变为 "why doesn't this code fragment show the value of the star I clicked?" 或者一旦你掌握了它 "how do I get the value of the element I clicked?"。最后一个是一个问题,您可以输入 Google 并期望得到一个不错的结果,因为您不是第一个遇到这个问题的人。尝试在 Firebase 上构建星级评分系统的人数要少得多。

终于

正如我已经说过的,您的脚本仍有问题。例如:我的 Firebase JSON logger:

每次单击单选按钮都会生成一对行
{"items":{"42":{"ratings":{"numRatings":"3"}}}}
{"items":{"42":{"ratings":{"numRatings":""}}}}

因此,每次我单击单选按钮时,似乎都会触发 Firebase 中的两次更改,第二次更改会撤消第一次更改的工作。我很确定我能弄清楚为什么会这样。但我希望通过以上课程,您将能够自己解决这个问题。

我的最终剧本:

(function() {
    var firebaseUrl = "https://your.firebaseio.com/rating";
    var itemId = 42; // TODO: look up Id of the actual item
    var rootRef = new Firebase(firebaseUrl);
    var itemRef = rootRef.child("items").child(itemId);
    var star = $('.rating');
    var numRatings;
    star.click(function() {
        itemRef.child("ratings").child("numRatings").set($(this).val());
    });

    var cumulativeRating;
    var averageRating;
    itemRef.child("ratings").on("value", function(ratingsSnapshot) {
        var ratingsData = ratingsSnapshot.val();
        if (ratingsData) {
            numRatings = ratingsData.numRatings;
            cumulativeRating = ratingsData.cumulativeRating;
            averageRating = cumulativeRating / numRatings;
        }
    });
})();

它也在 jsbin 上,我在那里进行调试:http://jsbin.com/lekifefuce/1/edit?js,output