Adding '+' to the end of Algolia instantsearch rangeslider's max value - javascript

I'm using Algolia's rangeslider from instantsearch.js with tooltips set to false. When the slider's maximum value is displayed (the value to the right side of the slider) (e.g: 2,000), I want it to display as (e.g: 2,000+) (with a "+").
I've tried accessing/resetting the value with jquery like this:
var $sliderMax = $('#my_slider_identifier .ais-range-slider--value').last();
And I've succeeded in getting a handle on the variable, but when I try resetting the maximum value from a custom widget's render() function (so it updates with each new set of results coming in) with the equivalent of $sliderMax.text('2,000' + '+'), nothing happens - I assume because the DOM is being re-written after my call..
If the rangeSlider is showing the maximum value (e.g: 2000), Is there a recommended way to put a '+' on the end?
EDIT:
To give more background: Though I have a range of values from 0-10,000+, the vast majority of the data is in the 0-2000 range, and I thus, truncated my data so that if it's >2000, it shows as 2000.
Also, incidentally and oddly, As a hack, I found that I can write to the DOM if I use a setTimeout of 0 ms (yes, there are stackoverflows on this) and re-do a JQuery selection:
setTimeout(function(){
$('#index_price_eur_day_i .ais-range-slider--value').last()
.text(MAX_PRICE_SLIDER + '+');}, 0);
I'd love to find a more-efficient solution.

I heard from Tim Carry of Algolia and he suggested that I try the :after pseudo element of CSS to fix this.
Indeed, I added this CSS and it always adds a + -- unfortunately even when the slider is not at the max value :/
#my_slider_identifier .ais-range-slider--value:last-of-type::after {
content: "+";
}
So it's not a perfect solution, but it may be "good-enough" - and it's not as ugly/inefficient as using jquery. If anyone has a better solution, please post it!

Related

Correct way to have calculated values in React.js

Setup
So basically I have 3 dimension fields (length, width and height) that are backed by state. I want to keep the state in inches but allow the user to switch the units on the display at will. Currently I'm only supporting inches and feet so I have a "dimension_unit" state that stores the currently displayed units and display_dimensions_multiplier that stores 1.0 for inches and 1.0/12.0 for feet (both are in state). I have everything working exactly as I want except for one thing.
Problem
All values I've tried have worked except when you try to use a decimal. Basically, in the background it's running throw the multiplier to get saved in state on change and then multiplies back in the value for the field which basically erases the trailing "." as you type so say you were trying to type 4.5, what you would actually get in the field as you typed is 45. But if you type 45 and then move the cursor between the 4 and 5 add the . you'll end up with 4.5...
My idea
The way I was thinking about solving it was basically have a state variable for the display_length and then have the regular length state as well then have the display_length stay the same unless they change units and have the length calculated and stored on change and then just persist that... and the same for height and width... but that seems very un-react-ive so what is the react-ive way of doing this? Or is that it?
Happy to post example code if needed, but there is a good bit of code for any component so... yeah... hopefully just the explanation is enough.
Edit1
Basic before fiddle: before
This is my idea I'm curious about: after
The main difference being:
_handleChange: function(ev){
ev.stopPropagation()
ev.preventDefault()
var key = ev.target.name;
var value = ev.target.value;
var indims = this.state.input_dimensions;
indims[key] = value;
this.setState({input_dimensions: indims});
value = (value / this.state.display_dimensions_multiplier);
var dims = this.state.dimensions;
dims[key] = value;
this.setState({dimensions: dims});
},
I think your solution is the right idea. A few similar ideas:
Only update your stored value when the input is committed (for example onBlur instead of onChange). You can apply generic realtime input validation to make sure it's a valid number.
Like you say use a separate "display" state (I would consider this an "input state") and when the component updates with the new stored value, only update the input state if it differs (when converted to the same units). This way you don't need to persist or worry about the "input state" outside the input components.
When the input has focus, don't update the input state when the stored value changes. When the input does not have focus or blurs, update the input state to the stored value.
I don't know that any of these solutions or the one you proposed is more "Reacty" than the others. I think it's really up to you.

Angular ngGrid Tree Control: Make a round trip on group expand

I am trying to use ngGrid to make somewhat of a "tree-control" which I can build dynamically by calling API's. ngGrid allows for grouping on rows, yet the nature of it requires that all rows be present at the beginning. This is unfortunate for the fact that an API to pull back all generation data for a File Integrity Monitoring system would be insanely slow and stupid. Instead, I wish to build the "tree" dynamically on the expansion of each generation.
I am trying to inject children (ngRows) into a group-row (ngAggregate) on a callback, yet I do not think that I am calling the correct constructor for the ngRows for the fact that the rows are ignored by the control
Through the use of the aggregateTemplate option on the gridOptions for ngGrid, I have been able to intersept the expansion of a group quite easily.
(maybe not easily, but still)
I've replaced the ng-click of the default template:
ng-click="row.toggleExpand()"
with:
ng-click="$parent.$parent.rowExpanded(row)"
I know that it's a bit of a hack, but we can get to that later. For now, it gets the job done.
The way that I discovered how to work my way up the $scope to my rowExpanded function was by setting a breakpoint in ngGrid's "row.toggleExpand" function and calling it from the template as so:
ng-click="row.toggleExpand(this)"
Once I retrieve the group I want, I call an API to get the children for said group. I then need to make the return as children of the row. I decided to do this by calling ngGrid's ngRow factory:
row.children = [];
for(var i = 0; i < childData.length; i++)
{
row.children[row.children.length] = row.rowFactory.buildEntityRow(childData[i], i);
}
row.toggleExpand();
... yet this does not appear to be working. The rows are not showing up after I do the expand! Why won't my rows show up?
Here's my current Plunker!
By the way
I've placed a debugger statement within the group-expand callback. As long as you have your debugger open, you should catch a breakpoint on the expansion of a group.
Thanks everybody!
I found my answer, I'm an idiot....
I got this control working, and then realized that it was a total hack, that I could have used the control the way it was meant to be used and it would have worked much better, had much better work-flow, and it would have saved me an entire day of development. If you are wondering how you use the control this way, the answer is that you don't.
I got the stupid thing to work by updating my data structure after the round trip and forcing the grid to refresh, pretty obvious. I had to set the grid options so that groups were always expanded and I had to control the collapser icon logic myself, outside of ngGrid. I never called row.toggleExpand. I also hid any rows with null values by a function call within an ng-if on my rowTemplate. After all that was said and done, I put my foot in my mouth.

I can't figure out the bug in this jQuery

The page having problems is...
http://schnell.dreamhosters.com/index.php?page=gallery#
I use Firebug to debug my jQuery and other code tidbits and it's been proving very useful for Javascript/jQuery debugging. However, at the same time, it's been one of the most frustrating debugging experiences I've ever gone through. I'm not sure why but sometimes it seems like I can copy someone else's methodology from a tutorial, character for character, and yet still come up with errors.
In any case, the problem here is that Firebug claims there is a bug on line 20 of the source.
missing : after property id
[Break on this error] $('#table').animate({"left: " + attr + "px"}, 2000);\n
This bug seems like a huge load to me because the colon is right there! And this is why debugging jQuery/Javascript is such a pain sometimes. The error messages are rather convoluted and sometimes don't even make a lick of sense to me. Or maybe that's just Firebug.
Either way, the goal I'm going for here is that I'm trying to dynamically change the animate function such that the more you click the left arrow, the further left the grid of images is shifted (due to the nature of the CSS 'left' property). I have Javascript variables and a hidden input tag to help hold essential values, but the major hurdle is getting the animate function to recognize these variables. Near as I can tell it will only accept string literals for arguments on how to animate and the documentation doesn't help me because it doesn't discuss the use of variables with animate, as if it's impossible.
Well, let's just say I don't like impossible, he likes to get in my way a lot.
The object literal passed to the animate function is not well formed, it should be:
$('#table').animate({left: attr + "px"}, 2000);
Edit: Looking closely to your code, you are also trying to get a value from an input with id = "count", and you have a missing # character to have an ID selector:
var count = +$('#count').val(); // get #count value as Number
You are also incrementing this count variable, but you should first convert it to Number, because the value attribute of input elements are string. (I did it using the unary plus operator on the right-hand side of the assignment).
You have to convert it to a number, because if you add two variables and one of them is a string, concatenation will take place:
"1" + 1 == "11"
Try:
$('#table').animate({left: attr}, 2000);
The "px" units of measurement here aren't necessary. That aside, the above is the correct creation of an anonymous object. You were just putting a string inside curly braces.

Setting the value (selected option) of a dijit.form.Select widget

I have a dijit.form.Select widget. It's tied to a data store, if that matters. It's filled with several options already. All I want to do is programmatically set its value. I can get its value using myWidget.attr('value') but if I try to do myWidget.attr('value', 5) for example (where 5 is one of the valid values), all it does is reset the widget to select the very first option, no matter what value I give it.
This seems to be a bug, and there aren't any tests or documentation which show how to accomplish what I want to. But is there some way, even if it's a dirty hack?
I'm using Dojo 1.4.0. Note that dijit.form.Select is the new name for dojox.form.DropDownSelect.
edit: I even tried resetting the widget with all new options, but it ignores the option which has selected = true and just selects the first option. There must still be a way though.
Even if your values are ints, if you set your integer to a string then this will work.
dijit.byId( 'my_select' ).attr( 'value', String( 5 ) );
Turns out it's a bug - if the option values aren't strings, it won't work (mine were integers).
Repost of my comment:
There is a test page here: dojo archive that you can mess with. Using fire-bug I used dijit.byId('s9').attr('value', 'CO') successfully on that page. That will set the "store-based" Select on that page.
But as you said I set it using a string and you were using integers so I didn't see the bug. Good catch.

How can I get the font size of an element as it was set by css

I'm writing a simple jQuery that to change the font size of an element by a certain percentage. The problem I'm having is that when I get the size with jQuery's $('#el').css('font-size') it always returns a pixel value, even when set with em's. When I use Javscript's el.style.font-size property, it won't return a value until one has been explicitly set by the same property.
Is there some way I can get the original CSS set font-size value with Javascript? How cross-browser friendly is your method?
Thanks in advance!
Edit: I should note that all the tested browsers (See comment below) allow me to set the the text-size using an 'em' value using the two methods mentioned above, at which point the jQuery .css() returns an equivalent 'px' value and the Javascript .style.fontSize method returns the correct 'em' value. Perhaps the best way to do this would be to initialize the elements on page load, giving them an em value right away.
All of your target browsers with the exception of IE will report to you the "Computed Style" of the element. In your case you don't want to know what the computed px size is for font-size, but rather you want the value set in your stylesheet(s).
Only IE can get this right with its currentStyle feature. Unfortunately jQuery in this case works against you and even gets IE to report the computed size in px (it uses this hack by Dean Edwards to do so, you can check the source yourself).
So in a nutshell, what you want is impossible cross-browser. Only IE can do it (provided you bypass jQuery to access the property). Your solution of setting the value inline (as opposed to in a stylesheet) is the best you can do, as then the browser does not need to compute anything.
In Chrome:
var rules = window.getMatchedCSSRules(document.getElementById('target'))
returns a CSSRuleList object. Need to do a bit more experimentation with this, but it looks like if m < n then the CSSStyleRule at rules[n] overrides the one at rules[m]. So:
for(var i = rules.length - 1; i >= 0; --i) {
if(rules[i].style.fontSize) {
return /.*(em|ex|ch|rem|vh|vw|vmin|vmax|px|in|mm|cm|pt|pc|%)$/.exec(rules[i].style.fontSize)[1];
}
}
In Firefox, maybe use sheets = document.styleSheets to get all your stylesheets as a StyleSheetList, then iterate over each CSSStyleSheet sheet in sheets. Iterate through the CSSStyleRules in sheet (ignoring the CSSImportRules) and test each rule against the target element via document.getElementById('target').querySelector(rule.selectorText). Then apply the same regexp as above..... but that's all just a guess, I haven't tested it out or anything....
This jQuery plugin looks like it will do the trick:
Update: jQuery Plugin for Retaining Scalable Interfaces with Pixel-to-Em Conversion
Github: jQuery-Pixel-Em-Converter
i had this problem once. i use this function to get the int value of a css attribute, if there is one.
function PBMtoInt(str)
{
return parseInt(str.replace(/([^0-9\.\-])+/,"")!=""?str.replace(/([^0-9\.\-])+/,""):"0");
}

Categories

Resources