Sharing reactive data between Meteor and Jquery / Javascript functions?

I have an array of image URLs and I´d want to use plain old javascript / jQuery (on the client, obviously) to test those URLs for a proper 200 status code and then pass to my template in a sort of “curated” URL list.

Which approach should I follow?? Due to the fact that I´d share Meteor and non-Meteor code and variables…

A clue on this will be highly appreciated :smile:

Bye

Ariel

In the end, it’s all just javascript. You can do anything you want outside of your template, store the result in a global variable, then access that variable in your template. You’ll just need to make sure you pay attention to the load order of your JS files, or consider putting your non-Meteor based JS in the client/compatibility directory (e.g. build your curated URL list via a script loaded under client/compatibility, store the result in a variable, then refer to that variable in your template).

Yes, I know that, but I was looking for a more “reactive” solution.
For example, I tried this:

  • call server method to get list of images URLs
  • on a template helper, I iterate the list
  • on each iteration, I create an Image object, pull it the URL and wait for the load / error to fire
  • if load is OK, “reactively” push the URL to another “reactive” list, which will be the one I´ll use on the template at last.

But then a problem arises! I cannot push to a reactive data source (Session, reactiveArray, whatever) from inside a jQuery or javascript ordinary function. The reactive datasource remains empty!

Thanks for replying!

Ariel

Okay, I think it will help if you can show some code outlining your issue. jQuery / javascript functions don’t prevent you from working with reactive data sources, so I’m probably just misunderstanding what you’re trying to do.

Ok, the basic approach I intended to use is (just showing the idea)

Templates.pics.helpers({
    curatedPicList: function() {
         var pics = [];
         Meteor.call("getPics", function(error,result) {
              if (!error) {
                    _.each(result, function(image) {
                          var img = new Image();
                          img.src = image;
                          img.onload = function() {
                               pics.push(image);
                          }
                    });
                    return pics;
              }
         });
        return pics;
    }
});

 <template name="pics">
     {{#each curatedPicList}}
        <img src={{this}} />
     {{/each}}
 </template>

In this case, curatedPicList always end up being an empty array…
I tried using

  var pics = new ReactiveVar();

and

  var pics = new ReactiveArray();

with no luck

BTW I´m considering using a client-only collection

Thanks in advance,

Ariel

Okay - I’ve thrown together a quick demo using ReactiveVar that should give you what you want. The code is below (I was going to throw this up on MeteorPad so you could see it working, but the site seems to be down for me right now).

pics.js:

if (Meteor.isClient) {

  Template.hello.onCreated(function () {
    this.pics = new ReactiveVar([]);
  });

  Template.hello.helpers({
    pics: function () {
      return Template.instance().pics.get();
    }
  });

  Template.hello.events({
    'click button': function () {
      var template = Template.instance();
      Meteor.call('getPics', function (error, result) {
        _.each(result, function (image) {
          var img = new Image();
          img.src = image;
          img.onload = function () {
            var pics = template.pics.get();
            pics.push(image);
            template.pics.set(pics);
          }
        });
      });
    }
  });

}

Meteor.methods({
  getPics: function () {
    return [
      'https://d14xs1qewsqjcd.cloudfront.net/assets/i/home-animation/cloud1.png',
      'https://d14xs1qewsqjcd.cloudfront.net/assets/i/home-animation/cloud2.png',
      'https://d14xs1qewsqjcd.cloudfront.net/assets/i/home-animation/cloud3.png'
    ];
  }
});

pics.html:

<head>
  <title>Pics</title>
</head>

<body>
  <h1>Welcome to Meteor!</h1>
  {{> hello}}
</body>

<template name="hello">
  <button>Click Me</button>
  {{#each pics}}
    <img src={{this}} />
  {{/each}}
</template>

MeteorPad is responding again - working demo here.

@hwillson : you beat me to it! :smile:

@ferroariel : basic pattern below:

Templates.pics.onCreated(function() {
  const instance = this;
  instance.pics = new ReactiveVar([]);
  Meteor.call("getPics", (error, result) => {
    const pics = [];
    if (!error) {
      _.each(result, image => {
        const img = new Image();
        img.src = image;
        img.onload = function() {
          pics.push(image);
        }
      });
      instance.pics.set(pics);
    }
  });
});

Templates.pics.helpers({
  curatedPicList: function() {
    const instance = Template.instance();
    return instance.pics.get();
  }
});

That would be once I’ve beat you to it for the 50 times you’ve beat me to it! :smile:

1 Like

Wow! Thanks so much! I´ll give it a try and let you know how it goes

Great! You made my day! Actually you opened my eyes on what
Template.autorun() can do !
Thank you very much :slight_smile:

1 Like