Can we create custom or reusable components in HTML?
My page has account search functionality which is implemented using HTML, JS, jQuery code. And my page consists of account search at different places. (Functionality is same tough). Only ID of the div changes at each time we using it.
So can we come up with kind of components in HTML?
Again, Writing the code in separate file and including at different locations wont work as ID changes at each area. ID matter as we make call to server, get data and update the fields etc.
Look into javascript templating. See mustache.js for one example.
e.g.
<script type="text/template" id="template">
{{#elements}}
<div id="{{id}}">
{{content}}
</div>
{{/elements}}
</script>
And your JavaScript:
var view = {
"elements":
[
{
id: "one",
content: "Lorem ipsum dolor"
},
{
id: "two",
content: "Sit amet consectetur"
}
]
}
var template = document.getElementById("template").innerHTML;
var output = Mustache.render(template, view);
console.log(output);
logs:
<div id="one">
Lorem ipsum dolor
</div>
<div id="two">
Sit amet consectetur
</div>
You can loop through objects, evaluate functions and insert them as text.
HTML is a markup language, not a programming language. Most likely you are looking for a template engine like haml
Following frameworks helps to solve the problem:
Mustache
HandleBars
I prefer to use HandleBar (which is written on top of Mustache).
If you use angularJS you can create a reusable html piece by making a separate html file with your component then calling it into your page as an element.
app.directive("elementName", function() {
return {
restrict: 'E',
templateUrl: "/Path/To/Html.file"
};
});
Then in every html page you want to use this component you just do the following:
<element-name></element-name>
Actually maybe you could use the separate js file, the implementation just needs to receive (maybe in the constructor, or if not a class, look up for a specific html tag) and use that required information when needed.
i love a good template engine, but you can use simple markup to decouple your logic from the html controls.
bootstrap does this using classes, and data- attributes work as well for more precise control.
you need to cleanup your code slightly; gather all the code you need, and detach all the refs to any given id. Usually, this is not difficult because you only have one or two spots that use the id, performing the rest of your operations using a variable.
wrap up all the code into one function that takes an element for it's only argument; this was formerly the one hard-coded to the id. move any IDs used in the code to classes or better yet, variables. change the css to reflect these classes and/or descendants of the widget class (more soon). at this point, you should be able to call the function and pass an element, and have it work. let's call it makeSearchFromElement().
function makeSearchFromElement(elm){
elm.onchange=function(e){ alert("searching for " + elm.value); };
}
once you can do that, all you need is an easy way to define them. let's use a class of "widget-search" as an example. add the class to any html element that needs the search functionality in your package.
<input class='search widget-search validation' id=search123 type=search />
now, all you have to do is find all the declared widgets in the HTML and send them to the widget maker somewhere in a site-wide JS file :
[].slice
.call(document.getElementsByClassName("widget-search"))
.map(makeSearchFromElement);
if you don't inject at the bottom of the body tag, you'll want to place that last bit in a ready() or onload() event.
that's all you need to do to enable any input to have the demo "search" ability simply by adding a class to the HTML, not a single line of CSS or JS needed to add each one. It lets you patch or upgrade each one on the site from one spot, and it reduces the amound of custom code to be shipped over the wire, making the page load faster than hand-binding or even template-ing them.
Refer this blog post. It elaborates "how to create reusable components" using Handlebar.js. Definitely worth reading it.
Below code is enough to add datetimepicker in your app.
{{datetime "d1" "Start Date"}}
jsFiddle for this
There is a quite easy way to do so by using the core html WebAPI features.
class ReusableHeader extends HTMLElement {
connectCallback() {
const currenctDirectory = this.attributes.currDir.value;
// Here you can access your attributes passed to the element
this.template = `<div>
<p>No brother <p>
<p> It should not be that much easy </p>
</div>`
}
}
customElements.define('my-header', ReusableHeader);
Ready to use
<my-header currDir="Home"></my-header>
The things you have to make sure before using it (keep it in header).
It should be defined first before using the element
The syntax is case sensitive so the element name should be like this () NO Capitals
ClassName should be like this ReusableHeader
Hope it works
Related
I am reworking an old app of mine and I am having issues with dom manipulation and basic selections within a vue instance.
Essentially I have information in a database that I load in via ajax.
Each record in the db has 2 sections. The header tab(title, time, date etc) and the body of the record(notes, ideas, etc)
When loaded, the header shows normally to the user but if they want to see what that note contains, they have to click on the header for the bottom to appear.
consider the following html:
<vuejs for loop>
<div v-bind:id='item._id' class="tabW" v-on:click="blueTabClick" >
<div class="blueTabMainColor">
<!-- header stuff here -->
</div>
<div class="notesOpenedW">
<!-- interior informaton here, HIDDEN BY CSS -->
</div>
</div>
<vuejs for loop ender>
This HTML is essentially inside a Vue for/loop directive, and generates however many "tabs(tabW)" as needed based on how much info I have in the DB
All I want the user to do is to be able to click whichever tab(tabW) they want information on, and for the notes show underneath(notesOpenedW).
I stripped my entire app and js and tried to keep it as simple a test as possible and even with the below, I still can't get anything.
here is my JS(JQ):
$(document).ready(function(evt){
$(".blueTabMainColor").click(function(){
$(this).next(".notesOpenedW").fadeToggle();
});
});
With this basic code, when I put it inside a Vue instance, via:
methods: {
blueTabClick: function (evt) {
evt.preventDefault();
$(".blueTabMainColor").click(function(){
//alert("you clicked me");
$(this).next(".notesOpenedW").fadeToggle();
});
}
}
It doesn't work, but if I take it out of the Vue instance, it works just fine.
how can I get this to work? or am I going about it the wrong way?
Vue will not cohabit happily with JQuery. You're $(this) will not work because you're not even in the document at that point, you're in pure js, virtual DOM, another universe. Then, if it did, the event listener you call may not exist. You will need to fundamentally transition this code to Vue if you want it to work, I fear.
You can achieve this by setting a ref on "notesOpenedW".
https://v2.vuejs.org/v2/api/#ref
I would strongly recommend to wrap this behaviour in a dedicated component
That would have the following content :
<div class="tabW" v-on:click="blueTabClick" >
<div class="blueTabMainColor">
<!-- header stuff here -->
</div>
<div class="notesOpenedW" ref="notesToggleDiv">
<!-- interior informaton here, HIDDEN BY CSS -->
</div>
</div>
And the method :
methods: {
blueTabClick: function () {
$(this.$refs.notesToggleDiv).fadeToggle();
}
}
Be aware that when using Vue, manipulating directly the dom is usually a bad idea.
As i showed you, it is possible to use jQuery with Vue if you absolutely need it (or cannot afford to rework more deeply your application).
Edit : Just found this article that i think would help you a lot :
https://www.smashingmagazine.com/2018/02/jquery-vue-javascript/?utm_campaign=Revue%20newsletter&utm_medium=Newsletter&utm_source=Vue.js%20Developers
I am curious as to which of the following is better practice (and why):
Injecting data as HTML 5 data attributes:
<div class="someDiv" data-for-popup="someData"></div>
Injecting a <script> into the file with some data structure
<script>
var myMap = new Map();
myMap.set('someKey','someValue');
</script>
In both cases, I would be using javascript/jQuery to look up the value, but which is the better solution?
A little background: I am creating a static page (no communication back and forth with the server besides servicing the page) so I can't use AJAX or any other server communication to service the data. The data being injected is used for a popup that is displayed on the page when "more information" is requested for a certain page object. In other words, I need the data to be present somewhere on the page, and I'm looking for the best avenue to do so, and I am also curious why that would be the best option.
Which one is better will depend on the use you want to give to that value, and on how the value is related to a particular element. So there's not a generic answer to your question, as it would go in a case-by-case basis. A good rule of thumb would be what some people commented:
If the data is useful and specific to that element, use data-*.
If there's no connection between the data and an element, use a variable in <script>.
But there's a misconception in your question, and you are missing (imho) a really important use case: data-* attributes are not exclusive for JavaScript, they can be seen and used in CSS (as part of a selector or to be used as a value), while variables inside a <script> tag are hidden to the CSS and cannot be used.
Right now data-* attributes are mainly supported in the content property for ::before and ::after but, at least in theory, they will be allowed in other properties making them more useful for styling purposes. For example:
div[data-columns] {
column-count: attr(data-columns);
}
That rule will save you having multiple rules in your CSS, it will simplify your code and make it more robust and easier to maintain... sadly, it is not supported yet.
Store in the DOM element only what is specific for it, such as text and/or title for the popup window.
In this way your JS function can rely on the element to construct the popup.
<button data-content="My popup content" data-title="My title">More information</button>
<button data-content="My 2nd content" data-title="My 2nd title">More information</button>
$("document").on("click", "button", function () {
var $this = $(this),
title = $this.data("title"),
content = $this.data("content");
//open your popup
//$this.popup({ title: title, content: content });
})
As others have said, you should only store short, specific information about the element with a data-*.
If you are looking to display a 'more info' style popup, containing lots of information. I would store that information in a hidden div that is referenced by the element. Then use JS to show that element.
<button type="button" data-target="#product-1-more-info">Product 1</button>
<button type="button" data-target="#product-2-more-info">Product 2</button>
<div id="product-1-more-info" style="display:none;">
More awesome info about product #1
</div>
<div id="product-2-more-info" style="display:none;">
More awesome infor about product #2
</div>
<script>
$('button').click(function() {
$($this.data('target')).show();
});
</script>
Of course this can be dressed up with animations and light box effects. But now you aren't storing giant amounts of data in the element and your JS is much simpler.
In JSF, what would be the "right" and "clean" way to integrate JavaScript i.e. into a composite-compenent? I am a fan of Unobtrusive JavaScript, and separating HTML from JS from CSS. What would be a good way to have as little quirks as possible? This is what I like the best so far:
<composite:interface>
// ...
</composite:interface>
<composite:implementation>
// ...
<script> initSomething('#{cc.clientId}'); </script>
</composite:implementation>
What I don't like is, to use language A to generate language B. Basically the same goes for event handlers and stuff. My favorite would be to attach those handlers via <insert favorite DOM JavaScript library here>. Is this possible? How do you do this kind of integration?
I'd say that what you've there is the best you can get, provided that you're absolutely positive that the HTML element's nature is so unique that you absolutely need to select it by an ID, every time again.
If the HTML representation is not that unique (I can imagine that a Facelets template or include file might contain application-wide unique HTML elements like header, menu, footer, etc, but a composite component which can be reused multiple times in a single view? I can't for life imagine that), then you could also consider using an unique classname and hook initialization on it.
E.g. /resources/composites/yourComposite.xhtml
<cc:implementation>
<h:outputScript library="composites" name="yourComposite.js" target="head" />
<div id="#{cc.clientId}" class="your-composite">
...
</div>
</cc:implementation>
with in the /resources/composites/yourComposite.js (assuming that you're using jQuery)
var $yourComposites = $(".your-composite");
// ...
You can if necessary extract the autogenerated HTML element ID for each of them in a jQuery.each():
$yourComposites.each(function(index, yourComposite) {
var id = yourComposite.id;
// ...
});
I'm writing an application with some client-side JS that I use to update the DOM reasonably often.
The thing is that doing something like:
$('#id').html('<div class="' + class + '">' + content + '</div>');
multiple times and leaving HTML lying randomly round your JavaScript isn't very pretty and difficult to maintain.
Is there a JavaScript equivalent (or alternate solution) to the way Lithium handles this in it's view helpers.
See:
http://li3.me/docs/lithium/template/Helper::_render()
http://li3.me/docs/lithium/util/String::insert()
For examples.
Basically in the PHP version you would make an associate array of common strings and a simple method to replace to replace certain marked parts of those strings with variables of the same name.
Another silly example (psuedo-code:)
var strings = {
'div': '<div {:attr}>{:content}</div>'
};
console.log(render('div', {id: 'newElem'}, 'Hello, World!'));
// Output: <div id="newElem">Hello, World!</div>
If you have any better suggestions on how you handle storing HTML in your JavaScript and keep it from going all over the place then I'd very much like to hear it.
Yes, use jQuery templates or Underscore templates (my favorite) or any other JS templating engine out there.
Also, check this question for a discussion on performance of templating engines: Improve jQuery template performance
If you don't want to use a templating system, and have many html snippets that must be created many times, then you can use another technique :
Create a div in your main html file, give it a specific css class or id
Using css, make this div invisible
Inside is div, create the "template" divs, each one will contain a "snippet", each one with proper class or id
Using js (jquery, whatever) when you need it, clone the "template" div, append it where you need it, and then customize it.
Using jquery this is very easy, and your template "divs" are asy accessible to any html designer.
I'm on a mobile device now, and posting code snippets is a bit difficult, but let me know if want some examples.
jQuery encourages you to dynamically construct your DOM nodes instead of doing string concatenation:
$("#id").html(
$("<div />").addClass(class).text(content))
In general, you can use the jQuery attribute methods to construct such nodes, and many of these methods take mappings as you say you like. For example:
$("#id").append(
$("<div />")
.attr({id: "newElem"})
.css({width: "100%", color: "red"}))
I've been using JSON to handle AJAX functionality in my rails applications ever since I heard about it, because using RJS/rendering HTML "felt" wrong because it violated MVC. The first AJAX-heavy project I worked on ended up with 20-30 controller actions tied directly to specific UI-behaviors and my view code spread over controller actions, partials and rjs files. Using JSON allows you to keep view specific code in the view, and only talk to view agnostic/RESTful controller actions via AJAX to get needed data.
The one headache I've found from using pure JSON is that you have to 'render' HTML via JS, which in the case of AJAX that has to update DOM-heavy elements, can be a real pain. I end up with long string building code like
// ...ajax
success: function(records){
$(records).each(function(record){
var html = ('<div id="blah">' + record.attr +
etc +
')
})
}
where etc is 10-15 lines of dynamically constructing HTML based on record data. Besides of the annoyance, a more serious draw back to this approach is the duplication of the HTML structure (in the template and in the JS).* Is there a better practice for this approach?
(My motivation for finally reaching out is I am now tasked with updating HTML so complex it required two nested loops of Ruby code to render in the first place. Duplicating that in Javascript seems insane.)
One thing I've considered is loading static partial files directly from the file system, but this seems a bit much.
I like the idea of templating. In my experience it can really clean up that messy string manipulation!
There are many solutions, for example, check out John Resig's (creator of jQuery):
http://ejohn.org/blog/javascript-micro-templating/
I would go with creating an HTML structure that contains placeholders for the elements you'll need to update via AJAX. How much structure it applies will depend on what you're updating; if you know the number of elements you'll have ahead of time, it would be something to the effect of
<div id="article1">
<div id="article1Headline"></div>
<div id="article1Copy"></div>
<div id="article1AuthorInfo"></div>
</div>
<div id="article2">
<div id="article2Headline"></div>
<div id="article2Copy"></div>
<div id="article2AuthorInfo"></div>
</div>
You then write code that references the id of each element directly, and inserts into the .innerHTML property (or whatever syntactically more sugary way jquery has of doing same thing). IMHO, it's not really so terrible to have to assign the contents of each element, the part that you don't want to have to sprinkle through your AJAX functions is the HTML structure itself; in your app the content is volatile anyway.
However, it looks like you might have a list of an unknown number of elements, in that case it may be that you'd need to just put in a placeholder:
<div id="articleList"></div>
In that case I don't really see a way to avoid building the HTML structure in the javascript calls, but a reasonable amount of decomposition of your javascript should help that:
function addArticle( headline, copy, authorInfo, i ){
createDiv( "article" + i + "Headline", headline );
createDiv( "article" + i + "Copy", copy);
createDiv( "article" + i + "AuthorInfo", authorInfo );
}
(not working code of course, but you get the idea,)
You could use the load function in jQuery;
This loads the content of a page into a div like this:
$('#content').load("content/" + this.href.split('#')[1] + ".html", '', checkResponse);
Just make a dynamic view and you are good to go...
Just happened to find exactly what I was looking for: Jaml