How can I break an eventListener if a change has occurred?

I created my own little image slider, and to make the bootloader work, I had to create addEventListener and then add the downloaded image to the DOM.

However, there is an error in this scenario: when the image is loaded and the user pushes it before it is loaded to see the next image, the event listener is still running in the background, and when the image is fully loaded, it overwrites what is currently The user is looking for time.

My HTML:

 <template name="ImageGallery"> {{#each galleryImages}} {{#if viewingImage}} {{> Image}} {{/if}} {{/each}} </template> <template name="Image"> <div class="image-in-gallery">LOADING</div> </template> 

Checking that the "image" that the user wants to see is the one we clicked on each iteration (showing it):

 Template.ImageGallery.helpers({ viewingImage: function() { var self = this var galleryImages = Template.parentData().galleryImages var renderImage = false var viewing = Template.instance().viewingImage.get() var posOfThisImage = lodash.indexOf(galleryImages, self) if (viewing === posOfThisImage) { renderImage = true } return renderImage } }) 

Inclusion of the user for viewing the following "image" and cyclization if we reached the goal:

 Template.ImageGallery.events({ 'click .click-to-see-next-image': function(event, template) { var viewing = template.viewingImage.get() var imageCount = this.galleryImages.length var nextImage = ++viewing if (nextImage < imageCount) { template.viewingImage.set(nextImage) } else { template.viewingImage.set(0) } } }) 

Loader:

 Template.Image.onRendered({ var imageUrl = Template.currentData().name + Template.parentData().name + '.jpg' var imageObj = new Image() imageObj.src = imageUrl imageObj.addEventListener('load', function() { $('.image-in-gallery').empty() $('.image-in-gallery').append($(imageObj)) } }) 

You can see where the problem is: empty() and append() , of course, overwrite the image the user is viewing and set it as downloadable.

I want to add a break somehow to the addEventListener function to see if the loaded image is really what the user wants to see. But there are two problems:

1) In this template, the variable ReactiveVar not available. Do I need to use the Session variable?

2) I have no idea how to break.

Can anyone help?

+5
source share
4 answers

I think there are two flaws in your code:

  • You never delete your load event when your template is destroyed. Therefore, even if your template is destroyed because you clicked to get the next image, the image is still loaded in your browser and the load event is fired. destroyed elements removeEventListener

  • You use $ in your onRendered . $ refers to the global DOM, while this. $ will only look for the local DOM of your template. If you used this.$ , This should have caused an error because your local DOM was destroyed and the wrong image was not shown.

Here's how I do it: https://github.com/darkship/ImageGallery

+2
source

Reading your question made me think that it is possible to restore the template settings without the need for this complex code in the templates and fix the main reason - the inability to understand which image is currently visible, and it is easy to set the next to be visible.

I found that it is best to forget about trying to access the parent content of data from child templates, because ReactiveVar in any case inaccessible through data contexts (as you have no doubt learned). And data context hierarchies are dependent on Blaze html, so it is not recommended to use them that way.

And other extremes have a Session variable that would be very global.

Fortunately, there is a middle way.

Define ReactiveVar outside the template namespace, and then it will be equally accessible to both parent and child templates. This works especially well if you are trying to write a package and do not want to pollute the global session namespace.

For example, put this in hello.html:

 <head> <title>rangetest</title> </head> <body> <h1>Welcome to RangeTest!</h1> {{> hello}} {{> rangeList}} </body> <template name="hello"> <p>And another test {{anotherTest}}</p> </template> <template name="rangeList"> {{#each ranges}} {{> range}} {{/each}} </template> <template name="range"> <p>{{name}}</p> <input type="range" value="{{value}}" min="1" max="10"> </template> 

and this is in hello.js

 if (Meteor.isClient) { anotherDict = new ReactiveDict('another'); anotherDict.set('hey',2); Template.hello.helpers({ anotherTest: function() { return anotherDict.get('hey'); } }); Template.rangeList.helpers({ ranges: function() { var ranges = [ { 'name':'first', 'value': 5 }, { 'name':'second', 'value': 6 }, { 'name':'third', 'value': 7 }, { 'name':'fourth', 'value': 8 } ]; return ranges; }, }); Template.range.events({ 'input input[type="range"]': function(e,t) { var value = parseInt(e.target.value); anotherDict.set('hey',value); } }); } 

You will see that reactive variables spread well between patterns.

This probably does not answer your question about event listeners, but I hope you can replace the event listener with the addition of manually using the event listeners Template.Image.events({ after implementing reactivity, as I suggested, those will be closely related to the specific a template for children, and there will be no way for them to be unpredictable.

ps I had an example of using ReactiveDict and range input values, since that was the question where I needed to solve a similar problem. I had all three research options, and this was what finally worked and felt in a more or less meteor way.

+4
source

I see, probably, the problem is in the architecture itself.

You must use two different data structures. Separate loading from rendering.

Let's say galleryImages is image data, you only need to iterate over to load images on the client side and insert them into another array loaded with images.

Then the template should iterate and interact with loadImages.

Sorry, but I am not familiar with the meteorite, I can not help with the code.

+2
source

Use the fictitious / fake / hidden img tag to bootstrap the next image and listen to the load event of this element after loading the image into this element, it is cached and you can put it in the viewer.

Hint: for fake item you should use

.fake-img {visibility: hidden; position: absolute}

for a hidden image tag, some browsers do not load images if the display: none rule

hope this helps.

But I would also agree that you should think about your architecture and try not to use jQuery dom manipulations in meteor

+1
source

Source: https://habr.com/ru/post/1238620/


All Articles