How to hide element in Vue-html-to-paper? - javascript

I need to hide some things when I do print pages. The 2 button signs do not want to be displayed when I want to print. I use plugin https://www.npmjs.com/package/vue-html-to-paper
Check my code:
<div id="printThis">
<h1> My tiyle </h1>
<button> I WAN'T TO DISPLAY THIS BUTTON IN PRINT!!! </button>
<p> My parag </p>
</div>
print(){
this.$htmlToPaper('printThis');
}
Question is simple. I wan't display button in my pdf paper.

I've read through the source code at https://github.com/mycurelabs/vue-html-to-paper/blob/master/src/index.js and it doesn't look like there's a variable built in to do this (which there really should be, maybe you could make a pull request?). But we can make one ourselves.
In the data section of your component, add a variable called printing:
data() {
return {
printing: false,
}
},
Edit your template to use it:
<template>
<div id="printThis">
<h1> My tiyle </h1>
<button v-show="!printing"> I WAN'T TO DISPLAY THIS BUTTON IN PRINT!!! </button>
<p> My parag </p>
</div>
</template>
(Note you can use v-if too. There's some upsides and some downsides.)
Then wrap the method call to the plugin in a method of your own to set and unset the variable. Use the callback the plugin documentation describes to unset the variable:
print(){
this.printing = true;
const options = null; // Set this if you need to, based on https://randomcodetips.com/vue-html-to-paper/
this.$htmlToPaper('printThis', options, () => {
this.printing = false;
});
}
And there you go.
I will say, you could probably write a plugin way better to do the same thing. It'd be nice to have a promise based approach, or at least some defined lifecycle events for print success or failure.

You can specify css file direction and in css file write your option.
Something like this.
__dir/app.js or __dir/main.js
import VueHtmlToPaper from 'vue-html-to-paper';
const options = {
name: '_blank',
specs: [
'fullscreen=yes',
'titlebar=yes',
'scrollbars=yes'
],
styles: [
'css/print.css',
]
}
Vue.use(VueHtmlToPaper, options);
#media print {
.hidden-print {
display: none !important;
}
}

Related

JavaScript: Instead of passing "this" as an argument, how can I make function which will be called on it as an object?

I'm JavaScript beginner and am still grasping some concepts around it, so sorry if the question is dumb or it's already answered, but I didn't know what to search for, as the language terminology is still kinda foreign to me (both JavaScript and English). Currently I'm trying to master "this" keyword and trying to minimize JS code inside HTML file and move as much as possible to external files.
This is my question:
Let's say I want to change paragraph's value from Hello World! to foo bar by clicking on paragraph itself, just by using "this" keyword and some JavaScript.
I can do it in external file like:
<!--index.html-->
<p onclick="setParagraphText(this, 'foo bar')">Hello World!</p>
----------------------------------------------
//script.js
function setParagraphText(paragraph, value) {
return paragraph.innerHTML = value;
}
Or inline, inside tag:
<p onclick="this.innerHTML='foo bar'">Hello World!</p>
My question is: is it possible to do a combination of these 2 ways, so that the p value is not passed as an argument, but instead the function is invoked on it as an object (as a similar to 2nd example), but still keep the method of doing it in external file (like in 1st example)?
Something along the lines of this.function(value) instead of function(this, value)
<!--index.html-->
<p onclick="this.setParagraphText('foo bar')">Hello World!</p>
----------------------------------------------
//script.js
function setParagraphText(value) {
//something with innerHTML = value; or whatever will work
}
Thanks in advance!
You can add a data- attribute to your p tag which would store the data you want your text to change to (ie: "foo bar"), and then use addEventListener to add a click event-listener to paragraph tags which have this particular data- attribute. By doing this, you're handing over the javascript logic to the javascript file, and thus limiting the JS written within your HTML file.
See example below:
const clickableElements = document.querySelectorAll('[data-click]');
clickableElements.forEach(elem => {
elem.addEventListener('click', function() {
const value = this.dataset.click;
this.innerHTML = value;
});
});
<p data-click="foo bar">Hello World!</p>
<p data-click="baz">Hello Moon!</p>
First of all, if you want to be able to call your function on this, you have to know what the keyword this here represents. One simple way to do it is to console.log it.
So, this is the DOM element you have your inline javascript on ! Confirmed here: this in an inline event handler. Okay, if you want to have more information, console.log paragraph.constructor.
So, it's a HTMLParagraphElement. That's what you would get if you call this:
document.createElement("p");
So, if you want to be able to call this.setParagraphText, it comes down to calling setParagraphText on an HTMLParagraphElement object. But in order to do that, HTMLParagraphElement has to implement it and one way to do this, as subarachnid suggested, is to add the function to its prototype so that it is shared by all instances of it. If you think this would be useful, take a look at Web Components.
Here is a link: Extending native HTML elements.
Basically, you do it like this (and the cool thing here is the functionality, that is changing its content when clicking on it, will be encapsulated within the class):
<!DOCTYPE html>
<html>
<body>
<script>
// See https://html.spec.whatwg.org/multipage/indices.html#element-interfaces
// for the list of other DOM interfaces.
class CoolParagraph extends HTMLParagraphElement {
constructor() {
super();
this.addEventListener('click', e => this.setParagraphText('new value'));
}
setParagraphText(v) {
this.innerHTML = v;
}
}
customElements.define('cool-paragraph', CoolParagraph, {extends: 'p'});
</script>
<!-- This <p> is a cool paragraph. -->
<p is="cool-paragraph">Cool paragraph! Click on me and the content will change!</p>
</body>
</html>
So you don't even have to write inline Javascript anymore!
But if you want to have it your way and add your inline javascript, it's fine.
<!-- Note the this.setParagraphText(), now it works! -->
<p is="cool-paragraph" onclick="this.setParagraphText('foo bar')">Cool paragraph! Click on me and the content will change!</p>
<!DOCTYPE html>
<html>
<body>
<script>
// See https://html.spec.whatwg.org/multipage/indices.html#element-interfaces
// for the list of other DOM interfaces.
class CoolParagraph extends HTMLParagraphElement {
constructor() {
super();
//this.addEventListener('click', e => this.setParagraphText('new value'));
}
setParagraphText(v) {
this.innerHTML = v;
}
}
customElements.define('cool-paragraph', CoolParagraph, {extends: 'p'});
</script>
<!-- This <p> is a cool paragraph. -->
<p is="cool-paragraph" onclick="this.setParagraphText('foo bar')">Cool paragraph! Click on me and the content will change!</p>
</body>
</html>
I don't know if that answers your question, but that should hopefully points you in the right direction.
For your code to work you would have to enhance the HTMLElement prototype with your setParagraphText method (which is basically just a wrapper for this.innerHTML = value):
HTMLElement.prototype.setParagraphText = function(value) {
this.innerHTML = value;
};
Now something like this should work:
<p onclick="this.setParagraphText('foo bar')">Hello World!</p>
But I would strongly advise against modifiying native prototypes (older browsers like IE 9 don't even allow such a thing afaik).
Currently I'm trying to [...] minimize JS code inside HTML file and move as much as possible to external files.
Then how about having no JS code inside your HTML? This lets you kill two birds with one stone:
document.getElementById("clickme").addEventListener("click", function() {
this.innerHTML = "foo bar"
})
<p id="clickme">Hello world!</p>
The listener you add with addEventListener will be invoked with this being the element that the listener was added on.
Dunno if this is what you're after, but this in the function is referring to the function itself, but you can send in a scope with .call(this, arguments) which means that referring to this in the function is actually the scope of the HTML element.
I'm showing two ways of how you can handle this, with either a data attribute or sending in a new value as a parameter.
function setParagraphText(newValue) {
this.innerText = this.dataset.text + " + " + newValue;
}
<p data-text="foo bar" onclick="setParagraphText.call(this, 'foo yah')">Hello World!</p>
Also read: Javascript call() & apply() vs bind()?

EmberJs - Is there a way to tell ember to insert the main-view after the rootElement?

Hi I would like to know if the is a way to tell ember to initialize immediately after the root Element?
For example I have this DOM Structure:
<div id="#bodyContent" class="ember-application">
<div data-name="ContentPlaceHolderMain">
</div>
<div id="ember357" class="ember-view">
</div>
</div>
But I Want ember to be first on the DOM:
<div id="#bodyContent" class="ember-application">
<div id="ember357" class="ember-view">
</div>
<div data-name="ContentPlaceHolderMain">
</div>
</div>
In my enviroment.js file I have this line:
ENV.APP.rootElement = "#bodyContent";
Is there any way to achieve this?
Ember uses appendTo to insert it's view inside root element. But you could override didCreateRootView of ember instance and change it to use prependTo. Have a look how Fastboot does this.
Update: This is an instance-initializer to overwrite didCreateRootView.
export function initialize(appInstance) {
appInstance.didCreateRootView = function(view) {
// overwrite didCreateRootView
};
}
export default {
name: 'prepend-to',
initialize
};
ember/glimmer does not provide an prependTo method. You have to implement that one on your own following the implementation of appendTo.
Please also note that didCreateRootView is a private hook. Don't expect that one to keep stable over time.
In general I would not recommend to go this path if there is any other way to achieve your goal. Please consider adding a container for ember at desired position. If you don't have control over HTML markup you might could add a container using jQuery before initializing ember.
Update 2:
import jQuery from 'jquery';
export function initialize(appInstance) {
appInstance.didCreateRootView = function(view) {
let containerId = 'ember-container';
jQuery('<div>').prop('id', containerId).prependTo(jQuery(this.rootElement));
view.appendTo(`#${containerId}`);
};
}
export default {
name: 'prepend-to',
initialize
};
This is not exactly what you've asked for but it's much easier to achieve. If your HTML markup looks like <body><div id="existing-content"></body> and body as default root element above instance initializer will add another div #ember-container before #existing-content and using this one as embers root element.
Update 3:
You find an ember-twiddle here: https://ember-twiddle.com/43cfd1ae978b810f2e7cf445f9a3d40c?openFiles=instance-initializers.root-element.js%2C
If you inspect DOM you will see that ember root element is wrapped by <div id="ember-container"></div>. This wrapper is append to rootElement. So it's before any existing content in rootElement. I guess it's not possible to define a custom index.html in ember-twiddle so I can't demonstrate this one. But you could easily test yourself.

Polymer, evaluate element based off object

I am using the tile example from polymers neon elements - and I am trying to make each expanded tile unique. My first try on how to do this was to pass a string in with the grid items like
{
value: 1,
color: 'blue',
template: 'slide-1'
}
And have that element be evaluated when rendered in a new element something like this. (this is the card template itself)
<template>
<div id="fixed" class$="[[_computeFixedBackgroundClass(color)]]"></div>
<div id="card" class$="[[_computeCardClass(color)]]">
<[[item.template]]></[[item.template]]>
</div>
This does not work - however I am wondering if there is some way to do this so I can load custom elements for the content of each card. For reference -https://elements.polymer-project.org/elements/neon-animation?view=demo:demo/index.html&active=neon-animated-pages , it is the grid example and I am trying to replace the content of each card once it is clicked on ( the fullsize-page-with-card.html, here is all the html for it - https://github.com/PolymerElements/neon-animation/tree/master/demo/grid ). Is this the wrong way of approaching this? Or maybe I have some syntax wrong here. Thanks!
Edit : OK, So I can send it through if i add it to the click to open the card like so
scope._onTileClick = function(event) {
this.$['fullsize-card'].color = event.detail.data.color;
this.$['fullsize-card'].template = event.detail.data.template;
this.$.pages.selected = 1;
};
and in the card's properties like so
template: {
type: String
},
So I can then evaluate it as [[template]] , however - the question still remains how to call a custom element (dynamically) using this string. I could pass a couple of properties and fill in a card or form so they are unique, but i think I would have much more creative freedom if I could call custom elements inside each card.
I have an element that allows referenced templates. There are a couple of others other there, but this one also allows data bindings to work: https://github.com/Trakkasure/dom-bindref

Reactjs append an element instead of replacing

I'm trying to iterate through a list/array/object of things: (I used coffeescript to keep it clear, jsfiddle of full JS here. but it's just a forEach)
pages = for page, each of #props.ids
$('#start').append("<div id='"+page+"' ></div>")
React.renderComponent page(title: each.title, text: each.text), $("#"+page)[0]
and append each of them, instead of replacing, leaving only the last item in the list.
Where the #start element is the starting container, and I want to populate it with multiple elements, but I need to give each their own container, otherwise they will all overwrite eachother, the default reactjs behaviour.
I'm wondering if there's a way to tell react to append instead of replacing the div.
I'd like to avoid using jquery if possible, and do it purely react-ly.
I though about giving the React.renderComponent page the initial list, and then iterate in the previously called template, however, then i'm facing a different problem, I have to return a reactjs element object, consisting of the whole list, which I really don't prefer.
I need for the initial call to create individual, independent react templates, appending eachother in a list, prefferably without any extra containers, or using jquery.
I think you're getting the concept wrong. React's renderComponent indeed renders a single component, somewhere. Doing this multiple times only re-renders the same component at that place (aka idempotent). There's no real "append" statement, at least not in the way you asked for.
Here's an example of what you're trying to achieve. Forgot about renderComponent in this. It's just to put the component somewhere.
/** #jsx React.DOM */
var pages = [{title: 'a', text: 'hello'}, {title: 'b', text: 'world'}];
var App = React.createClass({
render: function() {
return (
<div>
{
this.props.pages.map(function(page) {
return <div>Title: {page.title}. Text: {page.text}</div>;
})
}
</div>
);
}
});
React.renderComponent(<App pages={pages} />, whateverDOMNodeYouWantItToBeOn);
See what I did there? If I want multiple divs, I just create as many as I want to see. They represent the final look of your app, so making a same div be "appended" multiple times doesn't really make sense here.
Create a div with a class extradiv:
<div class="extradiv">
</div>
In CSS, Set It's display to none:
.extradiv {
display: none;
}
.extradiv * {
display: none;
}
In JS implement this function:
function GoodRender(thing, place) {
let extradiv = document.getElementsByClassName('extradiv')[0];
ReactDOM.render(thing, extradiv);
extradiv = document.getElementsByClassName('extradiv')[0];
place.innerHTML += extradiv.innerHTML;
}
Than you can use this in place of ReactDOM.render:
GoodRender(<Component>My Text</Component>, YourDOMObject)

Best way to find (i.e. set CSS) on DIV in table created by {{#each}} in Meteor?

I have this code working but wondering if I'm doing it the long way. Is there a more efficient way? I was hoping for a 1 line of code solution.
I want to change the color of a single DIV in a table created from a {{#each}} in Handlebars template. I came up with this callback, so every time isSharedByMe (which is a field in a Collection) becomes true, the templates reactivity sets the CSS color to green:
Template.showRepost.rendered = function () {
if (this.data.isSharedByMe) {
$( this.find('.repost') ).css( {'color': 'green'} );
}
return; // I like to explicitly show a return value so people know
// I'm not returning any specific value on purpose.
// Not sure if this kills efficiency (separate topic).
};
The Handlebars template is simple, I call this as a partial from my main template that has the {{#each posts}} call which produces the table:
<template name="showRepost">
{{show_repost_txt}}
</template>
{{show_repost_txt}} just shows returns text like, "Share", or "Already Shared".
This code above works, but what I was hoping for was to have 1 jQuery type line in my show_repost_txt helper to set the CSS color at the same time as changing text to "Already Shared".
But I could figure out how to set ONLY the current class .repost, since this.find is not available in custom template helpers, but is available in the .rendered callback (along with event handlers). I tried this jQuery with no luck:
Template.showRepost.show_repost_txt = function () {
if (this.isSharedByMe) {
// Type $(this) in the Browser console
// (it's the jQuery call to the DOM window object,
// I just can't figure out how to get the specific DIV I need.
$(this).find('.repost').css( {'color': 'green'} );
return "Already shared.";
}
};
Can you just make the css tag reactive like this?
<template name="showRepost">
{{show_repost_txt}}
</template>
and then add this to your css:
// Returns any extra classes to be applied to the link
Template.showRepost.extraClasses = function () {
if (this.data.isSharedByMe) {
return "theColorGreen"; // you will also need to add a 'theColorGreen' class to your .css file that matches this
}
return "";
};

Categories

Resources