How to change CSS properties in Meteor Templates? - javascript

I have been trying to fix this problem for days without finding a solution. I am working on a web application that aims at retrieving information from a db. I am using Meteor and blaze.
As a matter of fact, i would like to change css properties in a template event wether it deals with the css proporties of the click target element or any DOM element in the same template.
Here is my template code tag :
<button type="button" class="buttonsValue" value="{{value}}">
<div class="CheckButtonsLed"></div>
</button>
Here is my template event code :
Template.devicesConfiguration.events({
'click .buttonsValue':function(e, template){
//works well on the parent of the target of the click event :
$(e.target.parentElement).css('background-color', 'chartreuse');
//works well on the target of the click event :
e.target.style.backgroundColor="#ffcccc";
//does the same thing but with a different syntax :
$(e.currentTarget).css('background-color', '#ffcccc');
// Does not work ...
var CheckButtonsLed = template.find('.CheckButtonsLed');
CheckButtonsLed.style.marginLeft = '2 em';
}
});
It seems that it does not like the margin proporties while it works for the background property. my class element is my template devicesConfiguration.
I thought first it was because the target of the margin property is not the target of my click event but i tried to change the margin of the target of the event (.buttonsvalue) without results...
does someone have an idea ? thanks a lot ! :)

Well it works now. it deals with a matter of syntax :
i wrote
simpleInput.style.padding = '2 em';
instead of ...
simpleInput.style.padding = '2em';
to put in a nutshell, to change CSS Property of a DOM element (which is not the target of the event)in a meteor template :
Template.devicesConfiguration.events({
'click .buttonsValue':function(e, template){
var simpleInput = template.find('#simpleInput');
simpleInput.style.padding = '2em';
}
});
and don't put a div element in a button tag ...
Bye !

Related

How to add onClick on the component

I am using https://github.com/winhtaikaung/react-tiny-link for displaying some posts from other blogs. I am able to get the previews correctly. I want to capture the views count through onClick() but this module(react-tiny-link) doesn't seems to support the same, please help.
<ReactTinyLink
cardSize="large"
showGraphic={true}
maxLine={0}
minLine={0}
header={""}
description={""}
url={url}
onClick={() => this.handleViewCount(id)} />
I tried adding div around the component but it affects the css.
You can wrap your link with a div and attach your onClick callback on that div instead.
<div onClick={() => this.handleViewCount(id)}>
<ReactTinyLink
cardSize="large"
showGraphic={true}
maxLine={0}
minLine={0}
header={""}
description={""}
url={url}
/>
</div>
Your library - ReactTinyLink does not support onClick attribute.
Since you've tagged javascript - I can give you a small JS hack for the same.
Run the following code at the end of your React Rendering
var cards = document.getElementsByClassName('react_tinylink_card');
linksClicked = [];
for(var i = 0; i<cards.length; i++){
cards[i].onclick = function(){
linksClicked.push(this.href);
}
}
The above code will go through each and every cards and will attach onClick handlers on them, once clicked - the 'this' object will be your anchor tag's element, so I am storing it's href. (you're free to store anything you want)
In the following example - https://winhtaikaung.github.io/react-tiny-link/
I tried the same snippet - and got the following result
Hope this would be a good starting point for what you're trying to achieve.

Polymer - Get data-bound attribute value in repeating template

I'm having a bit of an issue here. I had a small amount of success with event.target.templateInstance.model.thing syntax to get the value of attributes from within a repeating template but I keep getting back undefined from this bit of code I have here:
downloadFunction: function (e) {
console.log("dl function clicked");
//get particular id of thing
var fu = e.target.templateInstance.model.s.soundId;
console.log(fu);
//^ returns "TypeError: Cannot read property 'soundId' of undefined"
}
And my repeating template is here:
<div layout horizontal wrap center center-justified>
<template repeat="{{s in carddata}}">
<sound-card image="{{s.imgurl}}"
quotetext="{{s.quote}}"
soundsrc="{{s.soundurl}}"
soundref="{{s.soundId}}"
downloadfunction="{{downloadFunction}}">
</sound-card>
</template>
</div>
Where carddata is just an array with my data in it. All of the values are generated fine so I know it's not an issue with my array. I'm just confused how exactly I'm supposed to target someting from within the repeating template? Am I calling it at the wrong time? Or am I messing up the syntax of the templateInstance bit?
If it matters, I'm trying to get it to work in an Android 4.4 webView using Apache Cordova. 4.4 webView doesn't appear to enjoy the shadowDOM terribly much.
Thanks!
edit: After some jiggery pokery with console logs, it appears that the sender value is referring to the div that I apply the on-click="{{downloadFunction}} to. Here's the template that I am repeating, if this provides any insight.
<div class="soundcard-container" vertical layout>
//can't target this one either on WebView 4.4, works on ChromeOS
<img src="{{image}}" on-tap="{{playAudio}}">
<div class="soundcard-bottom-container" horizontal layout center justified>
<span>{{quotetext}}</span>
//I have an 'a' tag for desktop browsers and the div tag is targeting my Android/iOS
//apps that I am exporting as a webView to using Apache Cordova. Webonly is hidden
//at the point where I'm trying to get my downloadfunction to work.
//console.log(sender) in my downloadfunction returns this div v
<div on-tap="{{downloadfunction}}" class="mobileonly"></div>
</div>
//just a hidden audio thing for web
<div style="display: none">
<audio id="{{soundref}}" src="{{soundsrc}}" controls preload="auto"></audio>
</div>
</div>
edit2 some console logs..
console.log(sender) and console.log(event.target) are both the same div that has the on-click event for my downloadFunction.. not sure if this should be the case.
console.log(e.target.templateInstance.model) returns my <sound-card> object, I believe like it should(?)
It's just when I add the specific .s.soundId that it's undefined. I'm not sure why it's unable to find it.. Maybe there's another way to get the specific soundId (or s.soundId rather) of that particular <sound-card> object?
I'll bet you want to refer to the "sender" of the event—not e.target. See the part about inSender at https://www.polymer-project.org/0.5/docs/polymer/polymer.html#declarative-event-mapping:
inSender: A reference to the node that declared the handler. This is
often different from inEvent.target (the lowest node that received the
event) and inEvent.currentTarget (the component processing the event),
so Polymer provides it directly.
This might fix it:
downloadFunction: function (e, detail, sender) {
console.log("dl function clicked");
//get particular id of thing
var fu = sender.templateInstance.model.s.soundId;
console.log(fu);
}
Alright I was able to fit this in a different way. I wasn't able to get e.target.templateInstance.model.s.soundId bit to work, so instead on the div that I call the event on (event.target) I gave it an attribute called data-soundid and passed it {{soundref}} from my original template and then where I repeat that template I simply made a function like so:
downloady: function (e) {
console.log(e.target.getAttribute('data-soundurl'));
}
Ta da! Very nice solution. Thanks to Eyal who suggested this to me in a previous question. It works like a charm. :-)
Here is working example of using templateInstance, with included selecting by dynamic ID: Plunk .
As for your code, can't tell why it's not working.
handleEvent: function(e, detail, sender) {
console.log('handleEvent');
console.log(sender.id);
//How to catch full_obj here,
//..as if first item is clicked: full_obj = {"firstName":"John", "lastName":"Doe"}
//console.log(e);
console.log(e.target.templateInstance.model.item.firstName);
//console.log(detail);
//console.log(sender);
this.instance_firstName = e.target.templateInstance.model.item.firstName;
this.instance_lastName = e.target.templateInstance.model.item.lastName;
//Selecting by dynamic ID
var clicked_element = this.shadowRoot.querySelector('#'+this.instance_firstName);
console.log('Selecting');
console.log(clicked_element);
//var second_element = sender.templateInstance.model.querySelector('my-second-element');
//var second_element = this.$.second_element;
}
Edit:
Event handling and data binding Docs

Duplicate div with script/style tags inside using JS

I have the following html code:
<table><tbody><tr><td>
<div id="div_1">
<style>...</style>
<div><label> 1 </label></div>
<div><input type="text" name="text_1"/></div>
<script>$("#text_1").mask("99/99/9999");</script>
<div><label><a onclick="javascript:insert_div()"> </a></label></div>
...
</div>
...
<div id="div_20">
<style>...</style>
<div><label> 1 </label></div>
<div><input type="text" name="text_20"/></div>
<script>$("#text_20").mask("99/99/9999");</script>
<div><label><a onclick="javascript:insert_div()"> </a></label></div>
...
</div>
</td></tr></tbody></table>
That generates this (from 1 to 20, actually):
What I need is to insert a whole new div when the user presses the arrow button. It should copy the div with scripts and styles and insert after them with a new number (e.g. 21, then 22, etc.).
This is purely an instructional example of an alternate way of doing this task. It is intentionally wordy to provide ideas.
Suggestion: Avoid attribute-based event handlers when using jQuery:
To clarify my first comment. If you use onclick=javascript handlers, you are placing the registration of the event in the HTML, separate to the actual handler in the script. The "jQuery way" is to apply the handler function to a selection of elements, using methods like .click() and the rather useful .on() which I use below. This makes maintaining pages easier as you are not hunting through the HTML for JavaScript snippets. jQuery event handlers also support having more than one handler, for the same event, attached to an element which you simply cannot do with onclick=.
Concepts shown:
Use a global counter for the next id number and simply increment it after each use
Use a delegated event handler to process the "add" clicks as the elements are added dynamically (so do not exist until later).
Use a template stored in a dummy <script> block to hold your template HTML (this text/template type is unknown so is ignored by all browsers. It also makes maintenance a breeze.
Replace placeholder markers in the template with the new id information
Convert the HTML to DOM elements using $(html)
Find descendants in the new row to add things like mask.
Append the new row
JSFiddle: http://jsfiddle.net/TrueBlueAussie/Lu0q0na2/2/
// Declare a global counter for our new IDs
id = 2;
// Listen for click events at a non-changing ancestor element (delegated event handler)
$(document).on('click', '.addnew', function(e){
// get the HTML of the template from the dummy script block
var template = $('#template').html();
// Change the template names etc based on the new id
template = template.replace('{name}', 'name' + id).replace('{id}', id);
// Increase next id to use
id++;
// Convert the HTML into a DOM tree (so we can search it easily)
var $template= $(template);
// Apply the mask to the newly added input - alter this to suit
$template.find('input').mask("99/99/9999");
// Append the new row
$('table').append($template);
// stop the link from moving to page top
return false;
});
I will be happy to explain any part of this if you have questions. I realise it may be a bit of a shock compared to the existing way of doing it you have :)
I give you the basic idea: the rest if left as an exercise as teachers say:
<script type="text/javascript">
var last_inserted = 0;
function insert_div(){
$d = $("#div_" + last_inserted).clone();
$d.attr('id', 'div_' + last_inserted++);
$("table").append($d);
}
</script>
And something else: <a onclick="javascript:insert_div()"> is probably not correct (untested).
Either: <a onclick="insert_div()"> or <a href="javascript:insert_div()">

Listen for changes in DOM

I am working on a reflection of part of my website. This is the relevant HTML:
<div id = "original">
<img src = "picture.png" alt = "A picture" id = "picture">
<p id = "text">Some text</p>
</div>
<div id = "reflection"></div>
My Idea is copying the content of div#original to div#reflection like this:
<script>
function reflect()
{
var original = document.getElementById("original");
var reflection = document.getElementById("reflection");
reflection.innerHTML = original.innerHTML;
}
</script>
I am aware, that this will make the HTML invalid, in the whole project I iterate through the elements copied and set the IDs to not have that side effect. I just thought that this would be unnecessary to include here.
The problem I have is that the HTML I want to reflect is dynamic, so it may change. Then the reflection is wrong. I have searched for an event handler for this, but haven't found one. The only one near I found was onchange, but apparently this listens to changes in the attributes, not the child elements. Is there another one for this, or did I just use onchange wrong?
Thank you for your help!
GeF
I am aware that I could add onchange to every element, but this seemed not good style to me.
The simplest thing you can do is add a callback to reflect() every time you change the contents of the #original.
If this is not an option, you can look into a MutationObserver (documetation), as suggested here: Is there a JavaScript/jQuery DOM change listener?

Wrapping a jquery validate span.error with nested divs

Heyo. This is my first stack overflow post because I am stumped and not finding many people who are trying to accomplish the same thing. I've tried using jquery .before(), .after(), and .wrap() to resolve this. I was initially using css :before and :after pseudo-elements, but as that won't work for legacy browsers, I've decided to use jquery.
I already have several forms on several pages with validation working. The error messages vary in length. We were using a static, one size background image on the default span element, so content was bleeding out on longer error messages. I built a flexible rounded corner series of nested divs to allow the error box to grow or shrink dynamically. The html I want to output is:
<div class="errorWrap">
<div class="errorTop"><span></span></div>
<div class="errorContent">
<span class="error">This is an error</span>
</div>
<div class="errorBottom"><span></span></div>
</div>
Here's an example of a solution I tried, but I'm still pretty new to javascript.
$('.error').before('<div class="errorWrap"><div class="errorTop"><span></span></div><div class="errorContent">');
$('.error').after('</div><div class="errorBottom"><span></span></div></div>');
Correct me if I'm wrong, but I think that I have the right idea with the jquery. But it's just kind of sitting there, not in any function being called. So I imagine that since the code isn't re-executing, it just doesn't show up. Is there an appropriate function to wrap this in? I'm certain I'm just not attacking this from the right direction. Any help is super appreciated.
the plugins "before" and "after" dont take html as string. you cannot start a div in one and close it in an other.
Either you take your current html and generate a new html string which you append where you want to or you use the "wrap" plugin http://api.jquery.com/wrap/
Using pure HTML
$(".error").html("<div class='beforeContent'>" + $(".error").html() + "</div>");
Using wrap (http://api.jquery.com/wrap/)
$(".error").wrap("<div class='beforeAndAfter'></div>");
If you want to show an error div after focus out of an input then you have to create it using html/wrap as Luke said and then you have to append it in ot the dom useing
$('.errorWrap').insertAfter('.focusedElement');
But there are other methods available to insert a new element like append/appendTo e.t.c,
I ended up fixing this problem on my own using jquery to create the div and it's nesting on pageload, the divs are generated with an error class that gives display:none. A custom errorPlacement function nests the error in the correct div. Then I used a custom validator highlight function to remove the class that hides the element. Then I used the unhighlight function to re-add the class to re-hide the div.
$(function() {
//Generate the elements and assign attributes
var errorWrap = document.createElement('div');
$(errorWrap).addClass('errorWrap hideError');
var errorTop = document.createElement('div');
$(errorTop).addClass('errorTop');
var topSpan = document.createElement('span');
var errorContent = document.createElement('div');
$(errorContent).addClass('errorContent');
var errorBottom = document.createElement('div');
$(errorBottom).addClass('errorBottom');
var bottomSpan = document.createElement('span');
//Place the elements directly after each dd element
$("dl > dd").append(errorWrap);
$("div.errorWrap").append(errorTop)
.append(errorContent)
.append(errorBottom);
$("div.errorTop").append(topSpan);
$("div.errorBottom").append(bottomSpan);
//Add custom validator defaults
$.validator.setDefaults({
errorPlacement: function(error, element) {
$(element).nextAll('.errorWrap').children('.errorContent').append(error);
},
highlight: function(element) {
$(element).nextAll('.errorWrap').removeClass('hideError');
},
unhighlight: function(element) {
$(element).nextAll('.errorWrap').addClass('hideError');
}
});
}
Although I'm sure this could have been done more shorthand, I really like this technique because I didn't have to update any of my pages that contained forms to get it to work. All of the nested divs are dynamically created by javascript, so I can include a global file to any page with forms and it will just work. Thanks for all who offered suggestions.

Categories

Resources