In this example, Knockout is working as intented. I'm looking for an alternative way of achieving the goal of having a dynamically filled grid with CSS class .last on every second item. In a way, I'm probably looking for a different approach.
JSFiddle with description
My problem illustrated on http://jsfiddle.net/96vdD/7/ and described here:
Three people pass through the foreach. Adding three divs to the grid.
Dynamically, Knockout assigns a css class of last to every second div that comes out of the foreach.
At the same time, each peoples visibility property decides whether or not (s)he will be displayed in the grid.
The CSS will strip the margin of every .last div in the grid, to prevent each second div from being moved to the next 'row'. A common layout technique in CSS.
See what happens when you change Charles' visibility to true and run the JSFiddle.
Problem
The second person in the example, Charles, is not shown in the grid (because his property visible is set to false). However, Denise is still moved to the next row.
Knockout adds a style="display:none" to Charles, but also applies the class="last" rule to him, while ideally I would like Denise to receive the class="last" as visually she is the second people in the grid.
Question
How can I have Knockout ignore !visible elements when applying the class="last" rule?
You can create a computed array of only visible people:
self.visiblePeople = ko.computed(function() {
return ko.utils.arrayFilter(self.people(), function(person) {
return person.visible;
});
});
then bind on it in your html:
<div class="wrapper" data-bind="foreach: visiblePeople">
Fiddle - http://jsfiddle.net/96vdD/8/
Related
I have a dropdown, and a list of elements that default to display:none with css.
Currently, when an element is selected from the dropdown it's changed to display:block
What I'm missing, is how to change the element back to display:none once a new one is selected. I know I could write a loop to constantly check every element and change it to display:none but that seems cumbersome.
My real problem has about 100 elements, and it seems wasteful to re-hide all of them when 99 of them will already be hidden.
Curious what the most elegant way to do this in jQuery (or javascript) is. A fiddle of what I have is here:
https://jsfiddle.net/3w66k51z/4/
Thanks!
I've added $(".sReport").hide(); before your .show() call in order to hide all of the elements.
jQuery.hide() will set the element's display to none
jsfiddle
You could add state so that you know the currently shown item (if any) and hide just that one element. I understand you don't want to hide all items when most of them will already be hidden.
Here is a simple implementation of this idea.
(I imagine your real problem involves many more hidden items than the fiddle. If not — maybe even if so — this may be a premature optimization, and there’s nothing wrong with calling .hide() or whatever on all items.)
Create array of your element then create a function to hide all elements but not the one you want to be display.
I have created 04 buttons and defined the active states for each button in the CSS. These active states are called in JS, so that it changes the div style property on clicked and then resets the property when the other button is clicked.
But this is not working for me.
I have created a fiddleDIV TAG for this. Kindly help.
Change your code from being called onLoad to be called No wrap - in <head>.
Because the functions were inside the onLoad function scope and not the global scope, they were not readable and no javascript was being called when clicking the buttons.
I didn't change any code, just the option on the left pane:
jsFiddle
Update
You also had a small flaw in logic causing the classes to become intertwined. Here's what you were doing:
When first object is clicked, set it's class to obj1_active. When second object is clicked set obj1's class to obj2 and set obj2's class to obj2_active.
As you can see, we're crossing obj1 and obj2 classes. To solve this, we'll keep track of the last object clicked (role) and the class that it should be when a new object is clicked (cname).
Here is the Demo: jsFiddle
Optimization
The code you have works, but it's not very optimized. We shouldn't need four different functions that all do essentially the same thing just to different elements.
In this demo, I simply add and remove _active from the className of each element when clicked: jsFiddle
Lets take it a step further and use multiple classes. This is useful to be able to generalize our CSS declarations. Lets use the default classes, and only append the active class onto the active element and remove it when a new element is clicked.
We'll also separate the _ in the classNames so that btn is its own class as well as mission. This allows for us to really clean up our CSS code to improve readability as well as not need to update multiple sections when we just need a simple background color update or something of that nature.
Here is the optimized demo: jsFiddle
Link Color
I'm not sure if you meant to do this, but you'll notice that the links sometimes start white then turn to black when clicked. This is because the :link pseudo selector only selects non-visited links. If you want it to select all links, then just use the <a> tag: Final jsFiddle
I'm working on text content that sometimes has different parts being related to each other, and I'd like to let user hover/mouseover any of the related parts, and accordingly highlight all the related parts at the same time with the same highlight color.
What's the quickest way to do this, assuming that I do have all the information (on the server) regarding which parts are related, prior to generating the content into HTML. I.e. I can put in the proper css or javascript to get the needed setup in ad hoc, per page basis.
The fastest way would be toggling a class on your body or a top container element and defining the CSS in such a way that it descendants are corrected colored/highlighted etc. This will be faster than adding/removing classes from each element in the association.
For example: if all related elements have the class "rel-1" then you can have a CSS definition like:
body.rel-1 .rel-1 {
background-color: #ddd;
/* .. other styles */
}
And on hover over any element with class rel-1, toggle the same class in the body/container element.
For example:
$('.rel-1').mouseover(function() {
$(body).addClass('rel-1');
});
$('.rel-1').mouseout(function() {
$(body).removeClass();
});
and so on..
If I understand your question, this can be done using jquery pretty easily.
First, I'd set up html elements with attributes. I'm using thisisfor, you can use (almost) anything. So if you can predetermine which 'group' each item belongs to on the server side, you can classify them with an attribute of your choice, and then whatever 'group'.
html
<div class="hoverme" thisisfor="group3">What group are we in?</div>
<div class="hoverme" thisisfor="group3">What group are we in?</div>
<div class="hoverme" thisisfor="group2">What group are we in?</div>
<div class="hoverme" thisisfor="group4">What group are we in?</div>
Then, using jquery, you can set up a hover event that checks an attribute, the thisisfor attribute in our case:
jquery
$("[thisisfor]").hover(function(){ /* anything with 'thisisfor' attribute */
var group = $(this).attr('thisisfor'); /* store its value as variable 'group' */
$("[thisisfor="+ group +"]").html(group); /* all with this group that was hovered....change the text (or whatever your plan is) */
});
See my example
But, yea, the possibilities are endless using attributes...
Slap me if I am going about this wrong, I am quite the beginner.
Here is my setup, which is very similar visually to Outlook's UI I guess.
Left pane (floating div) contains a list of containers you can click on (like emails). Right hand pane contains a set of non-visible containers that should become visible when their class is changed to a different css class.
I'm trying to set it up where if you click on the element in the left pane, it then performs an onclick javascript action (stored in an external .js file) that toggles the right div's class value between two css classes.
The onclick in the left pane div passes $_row['uniqueID'] to the function. That is the uniquely incremented column name. It is also the ID value of the right pane 's.
Putting this altogether, can someone direct me on how to do this?
left pane...
<div onclick=\"toggleMenu('".$row['uniqueIdentifier'],"'); \">
right pane...
<div id=".$row['uniqueIdentifier']," class=\"mL\">
css...
div.mL {display:none;}
div.mL.active {display:block;}
function toggleMenu(div){
$('#'+div).addClass('active');
}
jQuery has .addClass() and .removeClass() methods.
I think that's what you're after, let me know if not.
By not changing too much code I suggest doing this :
div.mL {display:none;}
div.mLactive {display:block;}
I erased the dot, so u have now 2 different classes.
So on clicking you just change the class of the div with the correct id to mLactive.
In Jquery this canbe done with $(#'theid').addClass('mLactive');
This only adds the new class. You also want to remove the previous class with $(#'theid').removeClass('mL');
Another way : $(#'theid').attr( "class" , "mLactive" ); Which doesn't require to remove the previous class. Your choice. Another advantage of this method is that javascript has a method to do that which doesn't require Jquery.
Jquery has also the easy options $(#'theid').show(); and $(#'theid').hide() btw.
When a draggable attribute is enabled on a parent element(<li>) I cant make contenteditable work on its child element (<a>).
The focus goes on to child element (<a>),but I cant edit it at all.
Please check this sample
http://jsfiddle.net/pavank/4rdpV/11/
EDIT: I can edit content when I disable draggable on <li>
I came across the same problem today, and found a solution [using jQuery]
$('body').delegate('[contenteditable=true]','focus',function(){
$(this).parents('[draggable=true]')
.attr('data-draggableDisabled',1)
.removeAttr('draggable');
$(this).blur(function(){
$(this).parents('[data-draggableDisabled="1"]')
.attr('draggable','true')
.removeAttr('data-draggableDisabled');
});
});
$('body') can be replaced by anything more specific.
If new contenteditable elements are not added in the runtime, one can use bind instead of delegate.
It makes sense that the draggable and contenteditable properties would collide. contenteditable elements, like any text field, will focus on mousedown (not click). draggable elements operate based on mousemove, but so does selecting text in a contenteditable element, so how would the browser determine whether you are trying to drag the element or select text? Since the properties can't coexist on the same element, it appears that you need a javascript solution.
Try adding these two attributes to your anchor tag:
onfocus="this.parentNode.draggable = false;"
onblur="this.parentNode.draggable = true;"
That works for me if I add it to the <a> tags in your jsFiddle. You could also use jQuery if it's more complicated than getting the parentNode.
Note: This is a workaround since I believe the inability for these two functionalities to work together resides in the HTML spec itself (i.e. the not working together thing is intentional since the browser can't determine whether you want to focus or drag on the mousedown event)
I noticed you explicitly set 'no libraries', so I will provide a raw javascript/HTML5 answer
http://jsfiddle.net/4rdpV/26/
This was my crack at it.
First of all, it might be better to include the data in one single localStorage item, rather than scatter it.
storage={
'1.text':'test 1',
'2.text':'test 2'
}
if(localStorage['test']){
storage=JSON.parse(localStorage['test'])
}
this creates that ability, using JSON to convert between object and string. Objects can indeed be nested
I also added (edit) links next to the items, when clicked, these links will transform the items into input elements, so you can edit the text. After hitting enter, it transforms it back and saves the data. At the same time, the list items remain draggable.
After saving, hit F12 in chrome, find the console, and look in the localStorage object, you will see all the data was saved in localStorage['test'] as an Object using JSON.stringify()
I tried my best to design this to be scaleable, and I think I succeeded well enough; you just need to replace the HTML with a container and use a javascript for loop to write out several items, using the iterator of your choice to fill the parameter for edit(). For example:
Say you changed storage to hold "paradigms" of lists, and you have one called "shopping list". And say the storage object looks something like this:
{
"shopping list":{
1:"Milk",
2:"Eggs",
3:"Bread"
}
}
This could render that list out:
for(i in storage['shopping list']){
_item = storage['shopping list'][i];
container.innerHTML+='<li draggable=true><a id="item'+i+'">'+_item+'</a> (edit)</li>'
}
Of course, if you were to edit the structure of the storage object, you would need to edit the functions as well.
The output would look something like this:
Milk (edit)
Eggs (edit)
Bread (edit)
Don't worry about the input elements if that worries you; CSS can easily fix it to look like it didn't just change.
If you don't want the (edit) links to be visible, for example, you can do this in CSS:
a[href="#"]{
display:none;
}
li[draggable="true"]:hover a[href="#"]{
display:inline;
}
Now the edit links will only appear when you hover the mouse over the list item, like this version:
http://jsfiddle.net/4rdpV/27/
I hope this answer helped.
Using html5sortable and newer JQuery events (delegate is deprecated, answer 3 years after initial question), bug still affects Chrome 37. Contenteditable spans and html5sortable seem to play nice in other browsers. I know this is only partially relevant, just keeping documentation on changes I've noticed.
$(document).on('focus', 'li span[contenteditable]', function() {
$(this).parent().parent().sortable('destroy'); // removes sortable from the whole parent UL
});
$(document).on('blur', 'li span[contenteditable]', function() {
$(this).parent().parent().sortable({ connectWith: '.sortable' }); // re-adds sortable to the parent UL
});