Data-Link to CSS background-image using a helper function not render - jsviews

I have a template which renders a background image to CSS within a <div> like this
style="background-image: url({{>~facilityImagePathDisplay(#data)}})"
Visual Studio doesn't like this and it's not a big deal but I wanted to see if there was a proper way to do this. I read through the documentation. Other stack questions and the below was created based off of the docs. This specifically links to all the docs Logic in JsViews css-tag
<div class="tile-image" data-link="css-background-image{:~facilityImagePathDisplay(#data)}" >
The above statement outputs exactly this to the div. <div class="tile-image" data-link="css-background-image{:~facilityImagePathDisplay(#data)}"> so it looks like it's not firing the helper function and rendering anything at all. Am I missing something?

It depends if you are running the link() method of JsViews, or simply the render() method of JsRender.
Your first version will works in both cases, but is simply rendering the CSS style.
The second version would only be used if you are running the link() method of JsViews - for data-binding etc. (So the background image could be dynamically updated if you data-binding triggers a new value).
For the data-link version, you need to makes sure the helper is returning a string that is not just "someUrl", but "url(someUrl)" - to provide the correct CSS data url syntax. In that case, the following should work:
data-link="css-background-image{:~facilityImagePathDisplay(#data)}"
Alternatively you can have the helper return just the "someUrl" string, but then include the "url(" and ")" strings in the template:
data-link="css-background-image{:'url(' + ~facilityImagePathDisplay(#data) + ')'}"

Related

How to force Meteor's Blaze to batch changes applied to #each block

I have a template which is mostly equivalent to:
<div class="line">
{{#each part in line}}
<span class="part">{part}</span>
{{/each}}
</div>
where the line: string[] is a partition of a single line into one or more parts. The problem is that when the content of line changes, the template tries to match old elements with new elements (which is fine) and applies changes one by one (which is not fine) to the DOM. In particular if the old value of line was ["Hello","world"] and the new one is ["Hello world"], then there is a short period of time when the user is presented new value of line[0] combined with old value of line[1], which is ["Hello world","world"]. Most of the time this gets unnoticed, but in case when the parts are long enough compared to the screen width, it might happen that <span class="part">Hello world</span><span class="part">world</span> does not fit into a single line, which in turn causes the whole further content to be moved one line lower, only to be later moved again one line higher when line[1] gets finally removed.
One solution which I currently use is to replace the whole #each loop with custom helper {{{ helpMeRenderThisLine line }}} which builds the HTML string manually, but obviously this violates separation of concerns and my code style.
I'm new to Meteor, but these are the directions I would like to investigate:
Is there a way to render a loop non-reactively? I've heard there was
something like #constant block, but it is no longer supported.
Is there a way to "batch" the whole updating process into a single DOM
reflow?
Is there a way to use the momentum package to remove the
flicker?
Is there a way to use a smaller Blaze template to render the
single line in non-reactive fashion?
Is there a way to render a loop non-reactively? I've heard there was something like #constant block, but it is no longer supported.
It is pretty straightforward to make a part of the the DOM non reactive: you just need to use a non reactive helper. E.g. in you template rendered or created function, you can attach your string array to your template instance (not a cursor using this.myStrings = Collection.find() but an array using this.myStrings = Collection.find().fetch(), this being your template instance).
You then return it in your helper using return Template.instance().myStrings
Is there a way to "batch" the whole updating process into a single DOM reflow?
Actually, it depends on how you refresh the original data. The above solution should do that. Keep in mind that you can nest templates to control the granularity of the DOM refreshes. Also make sure you control your subscriptions in case they are overlapping with the same published content. You can wait for every one to be ready using Template.subscribtionReady() (template level) or subscribtion.ready() (sub level)
Is there a way to use the momentum package to remove the flicker?
The flicker should go away if you refresh properly the data.
Is there a way to use a smaller Blaze template to render the single line in non-reactive fashion?
Not sure about what you ask here but a good practice would be to try to make component level templates, it might help in fine tuning the DOM rendering.
<div class="line">
{{#each part in line}}
{{> Part}}
{{/each}}
</div>

Binding using data-win-bind to backgroundImageUrl

I'm trying to bind the background-img: url('') property in a WinJS application.
I've got a view model property which is set to something dynamic like:
'images/' + myObject.name + '.jpg'
But I'm unsure how to use data-win-bind to set said property to the css property background-img: url(''); correctly.
My template is currently set like this:
<div class="item" data-win-bind="style.backgroundImage: backgroundImageUrl">
Where backgroundImageUrl is my view model property, but this does not seem to setting things correctly.
Any ideas as to how to bind to these properties?
Your data-win-bind syntax looks correct. So there could be two possibilities.
First, make sure you've called WinJS.Binding.processAll. That's necessary to set the binding context and set up the bindings described by data-win-bind attributes. Nothing happens without it.
Second, the value of the source's backgroundImageUrl must be a string in the form that CSS expects, that is, "url('')". It can't just be the relative path itself, like you would use with an img.src target.
To do this, either make the source's property in that form, or use a binding initializer/converter to add the url('') part automatically. For more on that, I suggest looking at Chapter 6 of my free ebook, Programming Windows Store Apps with HTML, CSS, and JavaScript, 2nd Edition, with the general data-binding discussion starting on page 299 and the initializer stuff starting on page 315.

What's the correct way to perform DOM manipulation in Meteor?

I'm using a package called Timeline
https://github.com/VeriteCo/TimelineJS
It works by having a placeholder such as
<div id="my-timeline"></div>
And then ultimately making a jQuery call to manipulate the div. Visually I'm seeing the timeline appear on the screen and then disappearing almost straight away. A similar effect occurs with the following simple example:
<div id="my-temp"></div>
combined with
$(document).ready(function() {
$('#my-temp').html('HELLO');
});
What's the correct way to perform this type of manipulation without having the resultant HTML disappear?
I believe you should use constant regions to prevent Meteor from re-rendering your div.
{{#constant}}
<div id="my-temp"></div>
{{/constant}}
Use Handlebars template, don't use jQuery's dom manipulation. If you have to use javascript dom manipulation, make sure to use Meteor.render().
http://docs.meteor.com/#meteor_render
Also you need to call your timeline creation code inside Template.myTemplate.rendered
http://docs.meteor.com/#template_rendered
Meteor Render is the right way to go as mentioned by Harry. Here's the link to the new documentation
http://blazejs.org/api/templates.html#Template-onRendered

JQuery load() function disables links and :hover effects?

I'm trying to load content from a different file into a div element within the current file using the jQuery load() function. Nothing fancy, just loading it and that's it. However the links that are contained in the loaded file become "disabled", you cannot click them, and pseudo-classes like :hover seem to be left out as well. Is there a solution to this?
$(document).ready(function() {
$("div.content").load("content.html");
});
let's say content.html contains just this line:
xxx
When it is loaded into the <div class="content"> the link is not clickable. It is colored according to the css, however the :hover effect doesn't work, and it behaves like normal text - not a link. This is a problem because the content I'm trying to load has a couple of links, and none of them work after being load()'ed.
I believe your issue is:
You use $('div.content').load('content.html') to send a request for content to (later) be inserted into the DOM.
You then run some code to specify handlers for nodes using $(document).click, $(document).bind etc - but this code runs before the new nodes have been added to the DOM.
New nodes are then added when the .load call completes.
The behaviour that you defined on all the origional nodes isn't being followed on the new nodes.
If that is the issue your're describing - then you need to add all the same bindings to the new nodes once they're created.
i.e. you need to provide a callback to add the bindings to the new elements:
function on_data_loaded() {
$('div.content ...').hover(.....);
// etc.
}
$('div.content').load('content.html', null, onloaded);
(note that's not a particularly clean way of doing it, but it should explain what needs to be done).

drupal - jQuery, can't select any elements via jQuery

I have a form and I add a js file via drupal_add_js() in the init code of the module.
I see the first debug message, but I can't seem to select any items from the document. I just get the jQuery object returned.
But when I add the same line into the firebug, it works.
console.log('called => init()');
console.log(jQuery('#quiz-form').find('#edit-next'));
If you're trying to retrieve the value from your form element, try:
console.log(jQuery('#quiz-form').find('#edit-next').val());
Getting the jQuery object as return is perfectly fine as methods like find actually return a jQuery object. You should check the length of the jQuery object that you are getting as return i.e. console.log(jQuery('#quiz-form').find('#edit-next').length);. If the length is zero, then of course the elements are not being found. In that case you should make sure that your JS code is being called after the DOM is ready i.e. you should either wrap your code with jQuery(document).ready or use Drupal behaviors.
I figured it out by chance. The jQuery object was trying to find the selected object before the page was initialized.
I was thinking drupal_add_js in the init module was enough.
BUt I had to wrap the jquery code in the Dom Ready function as well... as we always are supposed to do.

Resources