JSF Set CSS Style Using Javascript? - javascript

I have been looking with no success to see if I can dynamically apply a css style to JSF component or div using javascript. Is this possible.
This is pseudo code
<div style="myJSStyleFunction("#{myBean.value}")"> stuff </div>
And the function would return something like "position:relative;left:25px;"
I've had no luck and maybe it can't be done but would like a second opinion.
Edit:
I'm trying to see if I can keep a separation / reduce the coupling between the presentation/view and the model/controller. This is for indenting commenting or product reviews (to nest replies to comments or reviews). The most I really want to track is an integer on how deep a reply is. First level = 0 second level = 1, and so on. So a comment or product review would be 0 deep, a reply to the comment or review would be 1 and so on.
Then in the EL I wanted to call a javascript function and do something like
<script>
myJSStyleFunction(depth){
if(depth<=5){
var nest=20*depth;
var style="position:relative;left:" + nest + "px;";
return style;
}
}
</script>
And then then say for a third level comment (a reply to a reply) it would look like this:
<div style="position:relative;left:40px;"> stuff </div>
where
#{myBean.value}
evaluates to 2
I suspect like Daniel says I'll have to tightly couple the view but I'd rather not have to. I'd think there has to be a way. But maybe not.

I don't know where there are cleaner solutions for this. However this is one suggestion.
Assume your page looks like below and myBean.getValue() method returns an integer.
<h:form id="frm">
<div style="#{myBean.value}"> div1 </div>
<div style="#{myBean.value}"> div2 </div>
</h:form>
So you can do something like this at 'window.onload'.
<head>
<script>
window.onload = function() {
var childList = document.forms['frm'].childNodes;
for(var i = 0; i < childList.length; i++) {
if(childList[i].nodeName == 'DIV') {
var _div = childList[i];
var depth = _div.getAttribute('style');
_div.setAttribute('style', 'position:relative;left:' +(depth *20)+ 'px;');
}
}
}
</script>
</head>
Note: 1. In above sample code I assume all the DIVs inside the form should be indented.
2. For IE you may need to use _div.style.setAttribute('cssText','position:relative;left:' +(depth *20)+ 'px;')
3. Another solution for your question is using <script> tags immediately after your divs and putting the js part inside them. In this way you don't have to use fake styling style="#{myBean.value}" or window.onload event because you can directly call #{myBean.value} in your script.

I decided to skip the javascript approach and settled on a simpler and I think cleaner method to create the dynamic css classes for my situation. I already capture/calculate the depth value for each comment when it is entered. So I am just returning that value in EL and concatenating it to a 'base name' for the css class like so:
<div class="indent_#{(comment.commentDepth le 5) ? comment.commentDepth : 5}" >
comment comment blah blah blah
</div>
"indent_" is the base name for the css class. So for a 0 level comment it will have a class="indent_0". A reply to that comment will have class="indent_1".
I use the ternary so that if there are lot of replies under a given comment it doesn't indent right off the right hand side of the page. Even though you can keep going deeper, it will only indent up to 5 levels.
For my case at the moment, this is a simpler and cleaner method of adding some dynamically generated css class names. Right now I have to define 6 classes for this in the css file, but perhaps I'll figure out how to nest the boxes but it isn't a priority this works just fine for me for now.

Related

JS querySelector + ID with dynamic values

Im trying to make a simple quiz with a dynamic questions using Jinja (so a bit of python as well) + some SQL + JS.
Since im quite new to this, I was trying to do a simple "click here -> change color to green if your answer is the right one"
Here's the thing: to not complicate things, i want every answer to change the color to red (if wrong) or green (if right). Right know, thanks to this thread Javascript getElementById based on a partial string i manage to create a function that turns the right answer to green wih the code, no matter where the user clicks (as long its inside the question box answers):
document.querySelector('[ id$="{{ question.correct_answer }}"]').style.backgroundColor="rgb(0, 221, 135)";
I thought i could do something like "id$!=" and that would solve my problem, but that didnt work. So i tried to search for other stuff like the :not or not() selectors, but that showed me a lot of jquery stuff, which im not studying/learning right now. So, is there any way to write:
"if the id$ does not match the value {{ question.correct_answer }}, turn red" in plain JS?
Some important stuff about the code:
All answers have id="answer_a", "answer_b" etc.
That matches the way i save que "correct_answer" in the database, which comes exactly like the ID (so if the correct_answer is answer_d, i can call "{{ question.correct_answer }}" and that will always turn D into GREEN;
my HTML looks like <div class=question_answer id="answer_d" onclick="selecResposta()"> {{ question.answer_d }} </div> <br>. These are inside a DIV called "question_options" which i can also put the "onclick" function and everything works the same.
I can provide more information if necessary.
Thanks a lot for the help and sorry if this is something easy to solve. Any guidance (if you dont wanna say the answer) is quite welcome as well.
UPDATE:
Thanks to #connexo and #Vijay Hardaha, i manage to mix both answers and create a code that helped me. It might not be pretty, but its doing what i want so its perfect. Here's the solution:
html part:
<div class=question_answer data-answer="answer_a"> {{ question.answer_a }} </div> <br>
etc.etc
js:
function selecRightAnswer() {
document.querySelector("[data-answer={{ question.correct_answer }}]").style.backgroundColor="rgb(0, 221, 135)";
}
function selectWrongAnswer() {
const elements = document.querySelectorAll("div.question_answer:not([data-answer={{ question.correct_answer }}])");
elements.forEach(function (element) {
element.style.backgroundColor = "red";
});
}
Selects div with class question_answer when div has id=answer_a with an exact match.
document.querySelector("div.question_answer[id=answer_a]");
Selects div with class question_answer when div doesn't have id=answer_a with an exact match.
document.querySelector("div.question_answer:not([id=answer_a])");
document.querySelector will only selector first matched div. so if you have to work with all
unmatched with answer_a then you need to use document.querySelectorAll
and then you'll have to loop reach element and work with each element inside the loop.
Example
const elements = document.querySelectorAll(".box");
elements.forEach(function (element) {
element.style.color = "green";
});

HTML document pagination without jQuery

I have a large page having a lot of divs and all these divs are enclosed in a single div. And I have number links on the top of the page equal to the total enclosed divs I have. Now what I want to do is, on click on a number, I want to show only div corresponding to that number and hide all other.
links--> 1 2 3 4 5 6 7 .....
<div id="all">
<div id="mail1">..........</div>
<div id="mail2">..........</div>
<div id="mail3">..........</div>
<div id="mail4">..........</div>
<div id="mail5">..........</div>
<div id="mail6">..........</div>
.....and so on
</div>
I have to do it inside an HTML and that HTML will be stored and may be viewed offline as well, so cannot use jQuery here. Have to do it using JavaScript itself.
Could anybody help me with the JavaScript code here?.
<script type="text/javascript">
var divIds = ["mail1", "mail2", ..., "mailn"];
function showDiv(showId) {
for(var i = divIds.length; i--; ) {
if(divIds[i] === showId)
document.getElementById(showId).style.display = "block";
else
document.getElementById(divIds[i]).style.display = "none";
}
}
</script>
Then your links at the top will look like this:
1
Haven't tested it, but that's the idea. Downsides are you have to maintain the div in 3 places in code
In the var divIds array.
In the html tag itself.
In the links across the top.
You could write some javascript to generate all 3, taking away the maitenance part of it entirely.
As for using jQuery in an offline doc, the best route would probably be to include the text of the jquery.min.js file in the doc itself inside of <script></script> tags. That way you don't have to worry about paths and what-not.
You may do something like that (don't judge me on js coding style, i'm not a js ninja):
window.onload = function() {
var outer = document.getElementById("all");
for (var i=0; i < outer.childNodes.length; i++) {
outer.childNodes[i].addEventListener("click", doSomething);
}
function doSomething() {
// here you can run loop for changing display style for you divs
console.log(this.id);
}
}
I made an unobtrusive example without knowing the div ids:
http://jsfiddle.net/8pQzx/2/
Its more code but this is what you get if you dont want to use a js lib. ;)

How to create an effect higher up in the view than the logic that determines it?

I have a simple if statement in my view that returns x = 0 or 1. Based on this simple result, I want to change the styling of the div that contains the entire section.
<div>
conditional that returns x=1 vs x=0 (and a few displayed items)
based on this loop, restyle the div
</div>
Let's say, if x = 1, I want to make background-color:rgb(210,215,220);
How can I accomplish this? I am not experienced with Javascript but I'm sure any code required would be very simple. Thank you!
Add an ID to your DIV like:
<div ID="colorThis">
conditional that returns x=1 vs x=0 (and a few displayed items)
based on this loop, restyle the div
</div>
Then do this:
if(x==1)
{
​document.getElement​ById('colorThis').style.background = 'rgb(210,215,220)'​​​​;​​​​​​​​​​​​​​
}
<script>
if(x==1)
{
$("#divid").css("background-color","rgb(210,215,220)");
}
</script>
Include jQuery, and give the div's id to divid

Another jquery dynamic selector

I just asked a question here about selecting all id's of the form id_* where * is any string and id is the id of the element. I got a great working solution:
$("*[id^=" + id + "_]").each(function() {... // id is the element name
I need to take this one step further now:
All of my ids will be of the form: a_b_c ... where a b and c are arbitrarity strings (that do NOT contain a ''). So, now rather than selecting all the elems of the form id_* where * could be a_b_c ... I need only to select 1 level deep: i.e. all elems of the form id_a. So in other words it stops at the next ''. Is this possible?
As an example:
If my id is: first
And there exist id's: first_second, first_second_third
It will select only first_second
Sounds like you are storing too many values in the id of the field. With HTML5 we now have data- attributes.
Perhaps, you should be making use of data- attributes something like this to link them?
<div id="a">
</div>
<div id="b0" data-parentId='a'>
</div>
<div id="b1" data-parentId='a'>
</div>
<div id="b2" data-parentId='a'>
</div>
<div id="c" data-parentId='b1'>
</div>
It will still validate, as any non-standard attribute starting with data- will be considered valid.
See: http://ejohn.org/blog/html-5-data-attributes/
Your jQuery selectors can then make use of this new attribute, rather than trying to parse strings
Something like this would select all of a's children
var childrenOfA = $("div[data-parentId='a']);
What I ended up doing (and I'm open to faster implementations) is:
$("*[id^=" + id + "_]").each(function() {
//here I simply split the id and test the size of the array
//if its too large (i.e. too deep in the tree), I return true (to continue
// to the next iteration):
var row = $(this);
var split = row.attr('id').split("_");
if(split.length > SOME_PREDETERMINED_VAL)
return true;
//code here
});
I am not totally happy with this since it still traverses all elements (or would it do this anyway regardless of the filter in the each() function??).
This doesn't give you the whole solution, but you could try the attribute prefix selector or the attribute starts with selector
That will allow you to select any descendant of an element:
$("[id^='a_b_']").each(....
Will think how to remove the grandchildren etc, but this might get you started.
EDIT
I have just found that a similar question was asked about jQuery wildcards - this looks as if it will do what you need.
It seems like you are seriously overcomplicating this task. Let's say your structure is currently like this:
<div id="a">
<div id="a_b">
<div id="a_b_c">
</div>
</div>
</div>
Why don't you just do something along these lines...
<div id="a">
<div class="b">
<div class="c">
</div>
</div>
</div>
So, if I JUST wanted #a .b I would do:
$("#a .b").not("#a .c").show();
Makes it a bit more semantic and readable as well. Am I understanding what you're trying to do? Might need to shed a bit more light on what exactly you're doing
The obvious solution is changing your document, for example instead of
<div id="a"></div>
<div id="a_b"></div>
<div id="a_b_c"></div>
you could write
<div id="a" class="l1"></div>
<div id="a_b" class="l2"></div>
<div id="a_b_c" class="l3"></div>
and then select $('.l2[id^=a_]'). If that is not an option, you could try some sort of sieve scheme:
var set = $('[id^='+id+'_]'), i = 0;
while (i < set.length) {
var e = set.eq(i);
if (e.attr('id').substr(id.length+1).match('_')) {
set = set.not(e);
} else {
i++;
}
set = set.not($('[id^='+e.attr('id')+'_]'));
}
(I haven't tested, so there might be errors, and I'm not sure not is the one that subtracts from a result set, but you get the idea.)
It depends on the document structure and browser whether this will be actually faster than the naive implmentation of simply walking through the while set and skipping everything with two _ in the id. (High number of branches per node helps, and it will be probably faster on browsers which have a native implementation of the CSS3 prefix selector which jQuery can call on.)
update: fixed some mistakes. The logic might change depending on your structure, e.g. the innermost if branch is unnecessery if foo_bar always precedes foo_bar_baz.

Count Upwards for ID jQuery

I have the following HTML structure
<div id="test-1-yay"></div>
... bunch of code ...
<div id="test-2-yay"></div>
... bunch of code ...
<div id="test-3-yay"></div>
I was wondering how I can use jQuery to basically identify each of these "id's" and then apply some jQuery to them ? I'm new to this so little unsure ? Something like
if $('#test-1-yay' || '#test-2-yay' || '#test-3-yay') {
do stuff to all ID's
}
But the prob is I want this to continue as it could go to #test-201-yay, #test-202-yay etc ?
Thx
Why don't you add a class to the divs?
You could try something like:
$("div[id^='test']")
or
$("div[id$='yay']")
or try to combine the two
Manual
You could use a substring selector to get most of the way there:
var divs = $('div[id^=test-]'); // All divs with IDs starting with "test-"
...which would work better if you changed the naming convention a bit so the number was at the end. But I think I'd lean toward using some other aspect of the structure (the parent node), or a class, or a data-xyz attribute...
Edit A pair of substring selectors can do it:
var divs = $('div[id^=test-]').filter("div[id$=yay]");
That gets all of the ones whose IDs start with "test-" and then filters out the ones that don't end with "yay". Close, anyway...
you could do it like that:
$("div[id^=test-]").each(function(){ //selects all dives having the string 'test-' in it
$that = $(this)
$that.text($that.attr("id").split("-")[1]) //splits the sting by "-" and gives you out the middle part (in your case the number)
})
test it here http://jsfiddle.net/aj5Qk/1/

Categories

Resources