Each loop in html not working - pls help!

Somewhere like this, I guess:

<body style="background-color: #0b1c2f">
  {{> video}}
 </body>

Thanks. I have used this but still cant see the values inside the object e.g {{domainport}} is not visible in the html file. Below is the html code

<body style="background-color: #0b1c2f">
<section id="logo-section" class="text-center">
    <nav class="navbar navbar-fixed-left navbar-minimal animate" role="navigation">
        <div class="navbar-toggler animate" style="background-color: #7fff96; margin-top: 5px">
            <span class="menu-icon"></span>
        </div>
        <ul class="navbar-menu animate">
            <li>
                <a href="#snapshot" class="animate" id="singleCam">
                    <span class="desc animate"> Single Camera</span>
                    <span class="glyphicon glyphicon-stop"></span>
                </a>
            </li>
            <li>
                <a href="#snapshot" class="animate" id="fourCam">
                    <span class="desc animate"> Four Cameras </span>
                    <span class="glyphicon glyphicon-th-large"></span>
                </a>
            </li>
            <li>
                <a href="#snapshot" class="animate" id="nineCam">
                    <span class="desc animate"> Nine Cameras </span>
                    <span class="glyphicon glyphicon-th"></span>
                </a>
            </li>
        </ul>
    </nav>
</section>

<div class="container" style="background-color: #c5c6c7; width: 90%; height : 90%">
    <ul>
        {{#each urlList1}}
            {{> video}}
        {{/each}}
    </ul>
</div>
</body>

<template name="video">
    <li>
        <img src="http://{{domainport}}/videostream.cgi?user={{camusername}}&amp;pwd={{campassword}}&amp;resolution=32&amp;rate=0" style="width: 49.5%; height: 49.5%; float: left"/>
        <div>
            <a  id="left" target="main" style="float: left; margin-top: 10px"><img class="img-responsive" src="left.png" width="30" height="2" border="0" alt="" style="display:block;" /></a>
            <a  id="leftstop" target="main" style="float: left;margin-left: 5px;"><img class="img-responsive" src="leftst.png" width="39" height="39" border="0" alt="" style="display:block;" /></a>

            <a  id="right" target="main" style="float: left;margin-left: 5px;; margin-top: 10px"><img class="img-responsive" src="right.png" width="30" height="22" border="0" alt="" style="display:block;" /></a>
            <a  id="rightstop" target="main" style="float: left;margin-left: 5px;"><img class="img-responsive" src="rightst.png" width="39" height="39" border="0" alt="" style="display:block;" /></a>

        </div>
    </li>

</template>

BELOW IS THE HELPER FUNCTION#

Template.body.helpers({
        urlList1: function(){
            var urlList = [];
            var tokenId = '';

            tokenId = Cookie.get('Token');

            Meteor.call('cctvdetails', tokenId, function (error, result) {
                if (error) {
                    console.log(error);
                    //trigger an error message and raise an ALARM
                    //$('#autoclosable-btn-danger').prop("disabled", true);
                    $('.alert-autocloseable-danger').show();

                    $('.alert-autocloseable-danger').delay(5000).fadeOut("slow", function () {
                        // Animation complete.
                        // $('#autoclosable-btn-danger').prop("disabled", false);
                    });
                } else {
                    if (result == 'noDataReturnedByAPI') {
                        //$('#autoclosable-btn-warning').prop("disabled", true);
                        $('.alert-autocloseable-warning').show();

                        $('.alert-autocloseable-warning').delay(5000).fadeOut("slow", function () {
                            // Animation complete.
                            // $('#autoclosable-btn-warning').prop("disabled", false);
                        });
                    }
                    else {
                        $('.alert-autocloseable-success').show();

                        $('.alert-autocloseable-success').delay(5000).fadeOut("slow", function () {
                            // Animation complete.
                            // $('#autoclosable-btn-warning').prop("disabled", false);
                        });
                        urlList = result;
                        console.log('onRendered call: ' + urlList.length)
                        console.log('result domain port: ' + urlList);
                        var numberOfCameras = urlList.length;
                        Session.set('cameraCount', numberOfCameras);
                        if (numberOfCameras == 1) {
                            Session.set('templateType', 'singleCamView');
                        }
                        else if (numberOfCameras > 1 && numberOfCameras <= 4) {
                            Session.set('templateType', 'fourCamView');
                        }

                        else if (numberOfCameras > 4 && numberOfCameras <= 9) {
                            Session.set('templateType', 'nineCamView');
                        }
                        else if (numberOfCameras > 9) {
                            Session.set('templateType', 'moreThanNineCams');
                        }
                        console.log('inside the else: ' + urlList[1].domainport)
                        return urlList;
                    }

                }
            });


        }, })

THE SERVER METHOD CREATES THE URLLIST ARRAY LIKE BELOW

camList.push({
                    "domainport": domain+':'+port,
                    "camusername": username,
                    "campassword": password
                });

i think… remove the var in the var camList in the server.js that way i think it will be treated as global variable… HTH

It seems your urlList1 helper doesn’t return anything…

i think I can now understand what is going wrong. Since the meteor.call from the client to the server is an asynch call, there is nothing returned by the urlList1: helper function when its called and the return urlList in the helper is called even before the values are returned by the meteor.call.

So an empty object is being passed to the html. Is there any i can make the urlList1 helperr function return the value only after the asynch call is complete?

Check this post which reactively tracks the Meteor.call async callback in a helper. In that example (the second in the post), the call is made in the template’s onCreated callback, but it could be made elsewhere as long as the ReactiveVar is set up in the onCreated.

thanks. what is the line of code
this.distinct = new ReactiveVar(); stand for? is distinct a variable that can hold an array of objects?

I am referring to

Client

Template.getProjects.onCreated(function() {
  this.distinct = new ReactiveVar();
  Meteor.call('getDistinct', (error, result) => {
    if (error) {
      // do something
    } else {
      this.distinct.set(result); // save result when we get it
    }
  });
});

Template.getProjects.helpers({
  sites: function() {
    const projects = Template.instance().distinct.get();
    // turn our array of project values into an array of {project: project}
    return _.map(projects, project => {
      return {project}
    });
  }
});

<template name="getProjects">
  {{#each sites}}
    <div>Project: {{project}}</div>
  {{/each}}
</template>
Server

Meteor.methods({
  getDistinct: function() {
    return Meteor.wrapAsync(callback => {
      Sites.rawCollection().distinct('project', callback);
    })();
  }
});

Yes. In that example, it’s a reactive variable holding an array. It doesn’t matter too much what you’re storing in there, as it’s really just being used for its reactivity - to re-run the helper when the method returns data.

i am a bit confused with this code. I get the below error when I try to implement it in my code

Exception in delivering result of invoking ‘cctvdetails’: TypeError: Cannot read property ‘set’ of undefined
at http://localhost:3000/app/client/video/video.js?ce6054db903fbee769b230c9d0b3f133bf3906f8:47:42
at null._callback (http://localhost:3000/packages/meteor.js?431e407b21bf81d79061795e4fce958bea956e90:1007:22)
at _.extend._maybeInvokeCallback (http://localhost:3000/packages/ddp-client.js?82da06d8e1ea6342d823b2c5c3be071e96108c70:3508:12)
at _.extend.receiveResult (http://localhost:3000/packages/ddp-client.js?82da06d8e1ea6342d823b2c5c3be071e96108c70:3528:10)
at .extend.livedata_result (http://localhost:3000/packages/ddp-client.js?82da06d8e1ea6342d823b2c5c3be071e96108c70:4639:9)
at onMessage (http://localhost:3000/packages/ddp-client.js?82da06d8e1ea6342d823b2c5c3be071e96108c70:3373:12)
at http://localhost:3000/packages/ddp-client.js?82da06d8e1ea6342d823b2c5c3be071e96108c70:2742:11
at Array.forEach (native)
at Function.
.each.
.forEach (http://localhost:3000/packages/underscore.js?fa590de5090ceb4a42555b48562fd8f8e7035758:157:11)
at self.socket.onmessage (http://localhost:3000/packages/ddp-client.js?82da06d8e1ea6342d823b2c5c3be071e96108c70:2741:11)

i think its failing in this line#

this.distinct.set(result);

am I missing anything for this exception to arise?

distinct is the name of the ReactiveVar I used. You can call it anything you like, as long as it’s declared in Template.xxx.onCreated and referenced consistently elsewhere:

Template.xxx.onCreated(function() {
  this.anyname = new ReactiveVar();
  // ...
  this.anyname.set(someValue);
  // ...
});

Template.xxx.helpers({
  myhelper: function() {
    return Template.instance().anyname.get();
  });
});

CAn the set fail if I have not implemented the server method for synch behaviour?

I have converted my server method from asnyc to sync

    var convertAsyncToSync  = Meteor.wrapAsync( HTTP.get ),
        camListForUser = convertAsyncToSync( apiurl, {} );

but still get the error in the client
Exception in delivering result of invoking ‘cctvdetails’: TypeError: Cannot read property ‘set’ of undefined
at http://localhost:3000/app/client/video/video.js?7753a00427942d9c9ee3fdf418a30b4ff4d7a186:47:41
at null._callback (http://localhost:3000/packages/meteor.js?431e407b21bf81d79061795e4fce958bea956e90:1007:22)
at _.extend._maybeInvokeCallback (http://localhost:3000/packages/ddp-client.js?82da06d8e1ea6342d823b2c5c3be071e96108c70:3508:12)
at _.extend.receiveResult (http://localhost:3000/packages/ddp-client.js?82da06d8e1ea6342d823b2c5c3be071e96108c70:3528:10)
at .extend.livedata_result (http://localhost:3000/packages/ddp-client.js?82da06d8e1ea6342d823b2c5c3be071e96108c70:4639:9)
at onMessage (http://localhost:3000/packages/ddp-client.js?82da06d8e1ea6342d823b2c5c3be071e96108c70:3373:12)
at http://localhost:3000/packages/ddp-client.js?82da06d8e1ea6342d823b2c5c3be071e96108c70:2742:11
at Array.forEach (native)
at Function.
.each.
.forEach (http://localhost:3000/packages/underscore.js?fa590de5090ceb4a42555b48562fd8f8e7035758:157:11)
at self.socket.onmessage (http://localhost:3000/packages/ddp-client.js?82da06d8e1ea6342d823b2c5c3be071e96108c70:2741:11)

this is my oncreated code. Can you pls help understand why the ReactiveVar decalration is not working?

Template.video.onCreated(function(){
this.urlList = new ReactiveVar();

    var tokenId = '';

    tokenId = Cookie.get('Token');

    Meteor.call('cctvdetails', tokenId, function (error, result) {
        if (error) {
            console.log(error);
            //trigger an error message and raise an ALARM
            //$('#autoclosable-btn-danger').prop("disabled", true);
            $('.alert-autocloseable-danger').show();

            $('.alert-autocloseable-danger').delay(5000).fadeOut("slow", function () {
                // Animation complete.
                // $('#autoclosable-btn-danger').prop("disabled", false);
            });
        } else {
            if (result == 'noDataReturnedByAPI') {
                //$('#autoclosable-btn-warning').prop("disabled", true);
                $('.alert-autocloseable-warning').show();

                $('.alert-autocloseable-warning').delay(5000).fadeOut("slow", function () {
                    // Animation complete.
                    // $('#autoclosable-btn-warning').prop("disabled", false);
                });
            }
            else {
                $('.alert-autocloseable-success').show();

                $('.alert-autocloseable-success').delay(5000).fadeOut("slow", function () {
                    // Animation complete.
                    // $('#autoclosable-btn-warning').prop("disabled", false);
                });
                console.log('result[1]: ' + result[1].domainport)
                this.urlList.set(result);

                //urlList = result;
                //console.log('onRendered call: ' + urlList.length)
                //console.log('result domain port: ' + urlList);
                var numberOfCameras = urlList.length;
                Session.set('cameraCount', numberOfCameras);
                if (numberOfCameras == 1) {
                    Session.set('templateType', 'singleCamView');
                }
                else if (numberOfCameras > 1 && numberOfCameras <= 4) {
                    Session.set('templateType', 'fourCamView');
                }

                else if (numberOfCameras > 4 && numberOfCameras <= 9) {
                    Session.set('templateType', 'nineCamView');
                }
                else if (numberOfCameras > 9) {
                    Session.set('templateType', 'moreThanNineCams');
                }
                console.log('inside the else: ' + urlList[1].domainport)

            }

        }
        //return urlList;
    });

})

this is my helper

Template.body.helpers({
    urlList1: function(){
        return Template.instance().urlList.get();
    },

Your this.urlList.set(result); line is not scoped correctly for this (one reason I was using ES2015 syntax). What you should do is:

Template.video.onCreated(function() {
  this.urlList = new ReactiveVar();
  var self = this;
  // ... then around line 37 ...
        self.urlList.set(result);

Also, later on in your code, you are referring another urlList, the definition of which you have commented out (and really needs a var to scope it locally), so should be (something like):

            var urlList = result;
            //console.log('onRendered call: ' + urlList.length)
            //console.log('result domain port: ' + urlList);
            var numberOfCameras = urlList.length;
            Session.set('cameraCount', numberOfCameras);
            if (numberOfCameras == 1) {
                Session.set('templateType', 'singleCamView');
            }
            else if (numberOfCameras > 1 && numberOfCameras <= 4) {
                Session.set('templateType', 'fourCamView');
            }

            else if (numberOfCameras > 4 && numberOfCameras <= 9) {
                Session.set('templateType', 'nineCamView');
            }
            else if (numberOfCameras > 9) {
                Session.set('templateType', 'moreThanNineCams');
            }
            console.log('inside the else: ' + urlList[1].domainport)

However, this naming of two different things with the “same” name is confusing, and I may have missed the point! :smile:

i have changed the name to something else now to get the length. However I still get the exception like below

eption in delivering result of invoking ‘cctvdetails’: ReferenceError: urlList is not defined
at http://localhost:3000/app/client/video/video.js?fd6329e3223685960f5ed855b018bb9ee694d4ae:65:63
at null._callback (http://localhost:3000/packages/meteor.js?431e407b21bf81d79061795e4fce958bea956e90:1007:22)
at _.extend._maybeInvokeCallback (http://localhost:3000/packages/ddp-client.js?82da06d8e1ea6342d823b2c5c3be071e96108c70:3508:12)
at _.extend.receiveResult (http://localhost:3000/packages/ddp-client.js?82da06d8e1ea6342d823b2c5c3be071e96108c70:3528:10)
at .extend.livedata_result (http://localhost:3000/packages/ddp-client.js?82da06d8e1ea6342d823b2c5c3be071e96108c70:4639:9)
at onMessage (http://localhost:3000/packages/ddp-client.js?82da06d8e1ea6342d823b2c5c3be071e96108c70:3373:12)
at http://localhost:3000/packages/ddp-client.js?82da06d8e1ea6342d823b2c5c3be071e96108c70:2742:11
at Array.forEach (native)
at Function.
.each.
.forEach (http://localhost:3000/packages/underscore.js?fa590de5090ceb4a42555b48562fd8f8e7035758:157:11)
at self.socket.onmessage (http://localhost:3000/packages/ddp-client.js?82da06d8e1ea6342d823b2c5c3be071e96108c70:2741:11)

modified code is like this

 Template.video.onCreated(function(){
        this.urlList = new ReactiveVar();
        var self = this;
        testlist = [];
        var tokenId = '';

        tokenId = Cookie.get('Token');

        Meteor.call('cctvdetails', tokenId, function (error, result) {
            if (error) {
                console.log(error);
                //trigger an error message and raise an ALARM
                //$('#autoclosable-btn-danger').prop("disabled", true);
                $('.alert-autocloseable-danger').show();

                $('.alert-autocloseable-danger').delay(5000).fadeOut("slow", function () {
                    // Animation complete.
                    // $('#autoclosable-btn-danger').prop("disabled", false);
                });
            } else {
                if (result == 'noDataReturnedByAPI') {
                    //$('#autoclosable-btn-warning').prop("disabled", true);
                    $('.alert-autocloseable-warning').show();

                    $('.alert-autocloseable-warning').delay(5000).fadeOut("slow", function () {
                        // Animation complete.
                        // $('#autoclosable-btn-warning').prop("disabled", false);
                    });
                }
                else {
                    $('.alert-autocloseable-success').show();

                    $('.alert-autocloseable-success').delay(5000).fadeOut("slow", function () {
                        // Animation complete.
                        // $('#autoclosable-btn-warning').prop("disabled", false);
                    });
                    console.log('result[1]: ' + result[1].domainport)
                    self.urlList.set(result);
                    var testlist = result;
                    //urlList = result;
                    //console.log('onRendered call: ' + urlList.length)
                    //console.log('result domain port: ' + urlList);
                    var numberOfCameras = testlist.length;
                    Session.set('cameraCount', numberOfCameras);
                    if (numberOfCameras == 1) {
                        Session.set('templateType', 'singleCamView');
                    }
                    else if (numberOfCameras > 1 && numberOfCameras <= 4) {
                        Session.set('templateType', 'fourCamView');
                    }

                    else if (numberOfCameras > 4 && numberOfCameras <= 9) {
                        Session.set('templateType', 'nineCamView');
                    }
                    else if (numberOfCameras > 9) {
                        Session.set('templateType', 'moreThanNineCams');
                    }
                    console.log('inside the else: ' + urlList[1].domainport)

                }

            }
            //return urlList;
        });

    })

sorted it sorry my bad coding

Cool :smile:

You do not need to do this. The HTTP methods will execute natively in synchronous mode on the server if you do not specify a callback: http://docs.meteor.com/#/full/http_call

On the server, this function can be run either synchronously or asynchronously. If the callback is omitted, it runs synchronously and the results are returned once the request completes successfully.