What is the best way to refresh a div in Meteor without using a helper function

Working with JavaScript makes updating a div simple for me. I begin by displaying initial values for two divs in the image on the left. Upon clicking the test button, the values on the right change.

https://i.sstatic.net/UF0PZ.png

By clicking the test button, the counter increments by 1 and updates the div values as follows:

var ela = document.getElementById("a");
var elb = document.getElementById("b");
$("#" + ela.id).html("new value " + ela.id + " ");
$("#" + elb.id).html("new value " + elb.id + " ");

The next step involves rearranging the div order based on whether the counter is odd or even. In the case of an even counter, div 'a' (yellow) moves to the top, while div 'b' (grey) goes to the bottom. The order reverses for an odd counter.

To achieve this, I used small arrays to define the possible orders 'a,b' and 'b,a'. A helper function named 'order' determines which case should be chosen based on the counter's value (even or odd).

However, despite changing the div positions correctly, the text within the divs behaves unexpectedly. For instance, after the first click, the yellow div moving upwards from the bottom should display 'new value a', but instead shows 'new value b a', causing confusion.

Upon inspecting the divs in the console output, irregularities are observed. Meteor appears to be confused about the div ids, resulting in both divs sharing the same id, color, and being identified as both yellow and grey simultaneously.

https://i.sstatic.net/h8RjO.png

If anyone understands why this is happening and knows how to correct it, your insights would be greatly appreciated.

Although using helpers to update text content inside the divs could solve the issue, my ultimate aim is to develop a slider functionality using nouislider. Here is an example code snippet that demonstrates this:

var noUiSlider = require('nouislider');
var sliderHtmlElement = document.getElementById("a");
var options = {
    start: [0, 100],
    range: {
        'min': [0],
        'max': [100]
    }
};
noUiSlider.create(sliderHtmlElement, options);

For reference, here is my complete test code:

<template name="MyTemplate">
{{x}}
<br>
<br>
{{#each order}}
<div class="{{label}}" id="{{label}}" 
        style="background-color: {{color}};">
            start value {{label}}
        </div>
<br>
{{/each}}
<button class="test">test</button>
</template>

var order1;
var order2;

Template.MyTemplate.onCreated(function() {
Session.set("x", 5);

var or0 = [];
or0["label"] = "a";
or0["color"] = "yellow";

var or1 = [];
or1["label"] = "b";
or1["color"] = "grey";

order1 = [];
order1[0] = or0;
order1[1] = or1;

order2 = [];
order2[0] = or1;
order2[1] = or0;
});

Template.MyTemplate.events({
'click .test': function(event) {
var varx = Session.get("x") + 1;
Session.set("x", varx);
createSliders();
}
});

Template.MyTemplate.helpers({
x: function() {
return Session.get("x");
},
order: function() {
if (Session.get("x") % 2 === 0) {
return order1;
} else {
return order2;
}
}
});

function createSliders() {
var ela = document.getElementById("a");
var elb = document.getElementById("b");
console.log(ela);
console.log(elb);
$("#" + ela.id).html("new value " + ela.id + " ");
$("#" + elb.id).html("new value " + elb.id + " ");
}

Answer №1

To implement Blaze, it is necessary to import the .css file in addition to other dependencies:

// Import CSS for slider
import 'nouislider/distribute/nouislider.css'
import noUiSlider from 'nouislider'

You can then utilize Template's built-in jQuery to specify the target div where nouislider will be displayed.

Below is a sample template to demonstrate this functionality:

<template name="MyTemplate">
    <div>
        <div id="range"></div>
    </div>
    {{#if values}}
        <div>
            <span>values: </span>
            <span>{{values}}</span>
        </div>
    {{/if}}
    <button class="test">Show Slider</button>
</template>

You can trigger the rendering of a new nouislider into the " range" div by clicking the button:

Template.MyTemplate.events({
  'click .test': function (event, templateInstance) {
    createSliders(templateInstance)
  },
})

function createSliders (templateInstance) {
  // Use template's jQuery to get the target
  const range = templateInstance.$('#range').get(0)
  noUiSlider.create(range, {
    start: [0, 100],
    range: {
      'min': [0],
      'max': [100]
    },
    connect: true
  })
}

Reactive data can also be incorporated without using Session:

Template.MyTemplate.onCreated(function () {
  const instance = this
  instance.state = new ReactiveDict()
  instance.state.set('values', null)
})

Connect data with the noUiSlider update event to pass values to the state:

function createSliders (templateInstance) {
  // render slider...
  // ...
  range.noUiSlider.on('update', function (values, handle) {
    // Update values using a ReactiveDict
    templateInstance.state.set('values', values)
  })
}

Display the value in the template using a helper:

Template.MyTemplate.helpers({
  values () {
    return Template.instance().state.get('values')
  }
})

Customize the slider styling by importing your own .css files:

#range {
  width: 300px;
  margin: 14px;
}

Alternatively, dynamically style the slider using jQuery's css.


UPDATE: Ensuring Correct Rendering on Updated Display List

An issue exists as described which can be avoided by utilizing Template.onRendered to manage when rendering occurs.

The template has been extended as follows:

<template name="MyTemplate">
    {{#each sliders}}
        <div class="range">
            <div>
                <span>id:</span>
                <span>{{this.id}}</span>
            </div>
            <div id="{{this.id}}">
                {{#if ready}}{{slider this}}{{/if}}
            </div>
            {{#with values this.id}}
                <div>
                <span>values: </span>
                <span>{{this}}</span>
                </div>
            {{/with}}
        </div>
    {{/each}}

    <button class="test">Switch Sliders</button>
</template>

Defining when to render after initial DOM load using Template.onRendered:

Template.MyTemplate.onRendered(function () {
  const instance = this
  instance.state.set('ready', true)
})

And updating the helpers accordingly:

Template.MyTemplate.helpers({
  sliders () {
    return Template.instance().state.get('sliders')
  },
  values (sliderId) {
    return Template.instance().state.get('values')[sliderId]
  },
  slider (source) {
    createSliders(source.id, source.options, Template.instance())
  },
  ready() {
    return Template.instance().state.get('ready')
  }
})

Additional adjustments are needed in the onCreated section:

Template.MyTemplate.onCreated(function () {

  // Initial state of sliders
  const sliders = [{
    id: 'slider-a',
    options: {
      start: [0, 100],
      range: {
        'min': [0],
        'max': [100]
      },
      connect: true
    }
  }, {
    id: 'slider-b',
    options: {
      start: [0, 100],
      range: {
        'min': [0],
        'max': [100]
      },
      connect: true
    }
  },
  ]

  const instance = this
  instance.state = new ReactiveDict()
  instance.state.set('values', {}) // mapping values by sliderId
  instance.state.set('sliders', sliders)
})

A mechanism to switch and re-render sliders while managing their values:

Template.MyTemplate.events({
  'click .test': function (event, templateInstance) {

    let sliders = templateInstance.state.get('sliders')
    const values = templateInstance.state.get('values')

    // Remove existing sliders and events
    sliders.forEach(slider => {
      const target = templateInstance.$(`#${slider.id}`).get(0)
      if (target && target.noUiSlider) {
        target.noUiSlider.off()
        target.noUiSlider.destroy()
      }
    })

    // Assign current values as starting values for new sliders
    sliders = sliders.map(slider => {
      const currentValues = values[slider.id]
      if (currentValues) {
        slider.options.start = currentValues.map(n => Number(n))
      }
      return slider
    }).reverse()

    templateInstance.state.set('sliders', sliders)
  }
})

Complexities exist with multiple slider values but advantages include flexibility and organization.

  • (+) Pattern scalable for similar issues
  • (+) No need for autorun
  • (+) Separation of slider and value states
  • (-) Possible excessive rendering on re-rendering, impacting resource usage
  • (-) Complexity may increase on larger templates, emphasizing encapsulation importance

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

A mesh from Maya that has been exported with its skin duplicated within a Three.js environment

After exporting an animated skinned mesh from Maya using the Three.js exporter, I noticed that there is always a duplicate mesh combined with it that remains static and not animated. Despite trying various export settings and ensuring that no other mesh i ...

Guide to importing a glTF scene into your three.js project while using Internet Explorer 11

After successfully implementing a simple html code to load a gltf model using three.js and their gltfloader.js, I encountered an issue where it works flawlessly on Mozilla but fails to display on ie11 without any errors being thrown. Despite trying the es6 ...

Load Form with Json Data from LocalStorage Key-ID to Auto-Populate Fields

After successfully setting the ID in localStorage, I now need to retrieve and display only that specific record from my JSON data. The content of my localStorage is: This information is obtained from my JSON data after a button click. The challenge is us ...

Issue with JavaScript Replace not replacing second '<' character

I am attempting to swap out the < and > symbols of HTML tags with &gt; & &lt; by utilizing JavaScript. This is the code I am using: var sval = val.replace('&', '&amp;'); sval = sval.replace("<", "&lt;") ...

"Enhance your HTML table by selecting and copying cell values with a simple click and CTRL +

I stumbled upon a fantastic script for highlighting HTML table rows and it's working perfectly: I decided to modify the onclick event to onmouseover and included additional code to select a cell by clicking on it. Now I can select, check which one is ...

Looking to receive child events within a Vue 3 setup()?

Looking to convert the code below to use Vue 3 composition API. I am trying to listen for an event from a child component in a parent component that utilizes the render function. In Vue 3, $on has been removed and I'm unsure of how to replace it in t ...

Wrapping words in php code

Despite using word-wrap: break-word in the content-full class, the text is not appearing correctly. What could be causing this issue? Is there a solution to ensure long words break and wrap onto the next line? Interestingly, word-wrap: break-word works for ...

Swapping out the entire vue.js container

I have a custom vue.js widget that I initialize like so: var myWidget = new Vue({ el: '#widget-container', methods: { loadData:function() { // custom functionality here } }, }); The HTML structure is as f ...

Is it a guarantee that a React component will always update itself automatically when a method is invoked?

While you don't necessarily need to review the code below in order to grasp the question, it has been included for those who may benefit from visualizing the scenario. Each time the form is submitted, the addList method is triggered. I was surprised ...

Guide to resetting an input form upon submission in ReactJS

I'm encountering some challenges in resetting my input form upon submission. My goal is to have the input field clear out its value after a successful form submission, but for now, I'd settle for it simply resetting on submit in general. Unfortun ...

Tips for adjusting column positions in a table while maintaining a fixed header and utilizing both horizontal and vertical scrolling

Is there a way to display a table that scrolls both horizontally and vertically, with the header moving horizontally but not vertically while the body moves in both directions? I have been able to shift the position of the columns, however, I am struggling ...

In the ajax call, an empty JSON array object is sent as the data

Utilizing JSON data as a parameter for an ajax call: var startDate = dateFormatForSave($("#start_date").val().trim()); var arrayOfStudentsInfo = []; var table = $("#selected_students"); table.find('tr').each(function(i, el) { var rowId = $( ...

Tips for interpreting JSON information and showcasing it with the assistance of Ajax in JQuery?

There's a request made to the system via AJAX that returns JSON as a response, which is then displayed in an HTML table. The HTML code for displaying the data looks like this: <table id="documentDisplay"> <thead> <tr ...

Issue with Angular drag and drop functionality arises when attempting to drop elements within an n-ary tree structure displayed using a recursive template

I am currently exploring the functionality of angular material drag and drop. Within my application, I have implemented an n-ary tree structure. Since the specific form of the tree is unknown beforehand, I have resorted to using a recursive template in or ...

Steps for determining the grade earned by an individual

Seeking assistance with my Homework assignment as I am struggling to calculate it accurately. The code provided is what I have so far, and this is the task outlined by my teacher: Develop a webpage that displays the heading "Student Grades" and allows in ...

The SetCookie header was not properly stored within the system

Currently, I am developing a web application using node/express.js for the backend API and Vue.js for the frontend. Regarding authentication, I am implementing JWT and sending the value through an HttpOnly cookie. However, despite seeing the "Set-Cookie" ...

Troubleshooting: Unable to modify value with function in AngularJS

Why can't I change a value using a function in AngularJS? html: <div ng-controler='TestCtrl' id='TestCtrl'> <h1>Test: {{test.name}}</h1> <div ng-hide='showTest'> <div class=&a ...

adhesive section on the left side with a defined lower boundary

I have a contact div that I made sticky using Bootstrap affix. <div id="contactForm" data-spy="affix" data-offset-top="400"> However, I am unsure of how to limit its bottom to the top of the next div. In other words, I want it to stay in place when ...

I am interested in having the push notification feature function specifically for registered users

In an attempt to register the device for push notification using the PhoneGap plugin, I am encountering an issue. After the AJAX success action is called, the registration action does not alert the registration ID. Can someone help figure out what's g ...

Error encountered while trying to embed SVG file

My method involves utilizing an ajax call to fetch an htm file that constructs an SVG. Although the call retrieves the file successfully, the designated area where it should display only shows: https://i.sstatic.net/8G9IU.jpg Could this issue be related ...