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;
// ...
});
Related
This question already has answers here:
Is there a way to create your own html tag in HTML5?
(18 answers)
Closed 8 years ago.
Would it be possible to do the following
<body>
<main>
<!-- CONTENT -->
</main>
<foot>
<!-- FOOTER CONTENT -->
</foot>
</body>
if I then wrote some JavaScript that did something along the lines of the following. Please note that I don't want you to write the actual code that goes here. This is just a mockup of the core functionality.
for(elem inside main){
elem.makeItBig();
}
for(elem inside foot){
if(elem is img){
elem.makeItSmall();
}
}
I am aware of this post Is there a way to create your own html tag in HTML5?. But I don't really want to create tags to style them but rather to provide identifying attributes to the DOM which I can hook into using JavaScript. Imagine something kind of like a class, but used in a way that you can stitch lots of PHP generated parts together using these tags.
If you use a made up tag in HTML is it ignored by your browser or will it throw an error.
You can use your own tags as far as I'm aware.
You'd need to do some mucking about to get them to work in older IE browsers.
The more important point is - why on earth would you want to? It wouldn't make your code very maintainable or future-proof. Just use classes on proper elements.
Can you create custom tags? yes. Is it a good idea? not really because your tag may not be recognized by some browsers as a valid html standard. you can check this: http://www.w3.org/MarkUp/html-spec/html-spec_4.html#SEC4.2.1
For custom elements specifications you can look at standards specification for custom elements : http://w3c.github.io/webcomponents/spec/custom/
Although your approach seems nice, just think about changing the size of another group of elements ... you would probably use the same function so why not do this:
var makeItBig = function(elem){...};
for(elem in main){
makeItBig(main[elem]);
}
this way you won't have to create a new method for each element you need to change.
But if you really need it that way you can make it like this:
var makeItBigFunction = function(){var elem = this; ...};
// create new methods
for(elem in main){
main[elem].makeItBig = makeItBigFunction;
}
// make use of them
for(elem in main){
main[elem].makeItBig();
}
Notice that there is a big difference between DOM object's properties (or methods) and HTML attributes.
Read more about it: Properties and Attributes in HTML
Feel free to use HTML5 tags like <content>, <header>, <footer>, <aside> etc.
You can read more about them here: http://www.w3schools.com/html/html5_new_elements.asp in section "New Semantic/Structural Elements". Those should be considered as supported in most modern browsers. Actually, you may use any other custom tags, however their default properties (display, position etc.) may be unpredictable.
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
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"}))
As it's recommended, Javascript must be kept in a physically separate file (to be unobtrusive). So how do I access a particular element in particular page? should I detect those elements by id? that would mean 2 elements can't have the same id even if they are not located in the same page.
Well, for instance, using the Html helpers methods generates element's name + id from the model's properties. If I use the same model in several pages, many elements will have the same id. How can I target them in different pages. By the way, CSS work the same way.
EDIT
Let's say I've this
<% = Html.TextBoxFor(x => x.FirstName)%>
It will generates
<input type = "Text" name = "FirstName" id = "FirstName"/>
Let's say I've this textbox in 2 differen pages. If want, for instance, to disable the textbox located in page A, how do I do it knowing they are two of them in 2 different pages. How do I discriminate them from my external javascript file?
Thanks for helping
I suggest that for each page the uses the same model, you create a wrapper div
<div class="pageA">
// the model stuff here
<% = Html.TextBoxFor(x => x.FirstName)%>
</div>
<div class="pageB">
// the model stuff here
<% = Html.TextBoxFor(x => x.FirstName)%>
</div>
and then use Jquery selectors to get the correct element $(".pageA input[name='FirstName']") (not sure if this syntax is correct).
You cannot have multiple elements on the page with the same id. That isn't valid HTML.
So when you use the same HTML helper multiple times, you need to pass different names:
<%: Html.TextBox("Foo", Model.Foo) %>
<%: Html.TextBox("Bar", Model.Bar) %>
Correct me if i'm wrong, but are you saying, you have some elements with the same id, on multiple pages, that you want to attach different behaviour to? If so then this could help you out. if not, then what Craig said.
You can use more specific selectors, or give your selectors context
have a look at the documentations here: http://api.jquery.com/jQuery/
under this header:
jQuery( selector, [ context ] )
it explains a bit about selects and context. you should be able to use this and some creative page building to target the right element with your jQuery.
So you have two files, each with a text field with the id "FirstName". When you're script runs on Page A you want to disable the field, but not when your script runs on Page B.
Is the structure of the two pages identical? I suspect not if you're handling these fields differently. Use the context to your advantage. Like if the one on Page A is in a div with id "thisDiv" and the other is in a div with id "thatDiv" you could document.getElementById('thisDiv'). If you get an element then disable the field, if not do nothing.
If you want a more specific answer you're going to have to give us more context.
Well JavaScript may be kept in a separate file or not, but it is definitely included as part of the HTML send to the browser for a particular page. I Hope I've understood your question, but, generally if you have you JavaScript code in a file, lets say utils.js then in your html generated should include (probably within the <head> tag):
<script type="text/javascript" src="/path/to/utils.js"></script>
The script get included in the page, and when the browser encounters this, it loads and then runs the script, for that page. Therefore, it is not important what the ids for elements on different pages are.
Does that make sense, or have I completely misunderstood your question?
Update:
Ok, so based on your comments, I think I understand. You have
//Page 1
//When loaded, this input should flash blue via javascript for example
<input id="firstName" .../>
And
//Page 2
//When loaded, this input has some other fancy effect/behaviour
<input id="firstName" .../>
Well in this case, as far as I see, there are only 2 types of answers. Have two seperate external js files, one per page and this way you can change to your hearts content ...OR... have some sort of hidden field in your page that tells your script what page it is looking at (this seems hacky)
<input type="hidden" value="page1"/> //etc..
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