angular directive always adds attributes to wrapping outer element - javascript

I'm new to angular and banging my head against the wall over this:
I am making a re-usable slider element which will generate an input type="range" wrapped in a label.
I want the attributes defined on the directive to be applied to the child input element defined in the directive's template, which they do, but they also get added to the wrapping label element. This seems messy and I think I'm missing something fundamental.
What is the best way to do this? do I need to use a compile function, that seems like it would defeat the purpose of having a template in the directive?
current html:
<slider min="0" max="1000" step="1" label="foo" ng-model="slider1" value="750">
</slider>
current directive:
myApp.directive('slider', function() {
return {
restrict: 'AE',
scope:{
data:'=ngModel',
min:'#',
max:'#',
step:'#',
label:'#',
value:'='
},
replace: 'true',
template: '<label>{{label}}<input min="{{min}}" max="{{max}}" step="{{step}}" type="range" ng-model="data" value="{{value}}" />{{data}}</label>'
};
});
current output:
<label min="0" max="1000" step="1" label="foo" ng-model="slider1" value="250" class="ng-isolate-scope ng-pristine ng-valid ng-binding">
foo
<input min="0" max="1000" step="1" type="range" ng-model="data" value="250" class="ng-pristine ng-valid">
</label>
desired output:
<label>
foo
<input min="0" max="1000" step="1" type="range" ng-model="data" value="250" class="ng-pristine ng-valid">
</label>

This is strange. Though i haven't tried, i would guess the replace is adding the attributes of the slider element to the first element in your template which is label. Try adding another element in the template before your label, and try if replace: false does the same
<div class="filler></div><label>{{label}}<input min="{{min}}" max="{{max}}" step="{{step}}" type="range" ng-model="data" value="{{value}}" />{{data}}</label>
UPDATE
Since replate:true always seems to add the attributes, you will probably have to use replace:false, and create a compile or link function that deletes the element manually as in
link: function (scope, element, attrs) { angular.element(element).remove();

I see this question is a few months old so you've probably moved on now but I kinda just want to answer it anyway. Maybe it'll help other people.
I've only been using AngularJS for around 3 weeks now but I get the feeling that the messy output you're getting is typical of AngularJS and after all it's only messy if you're delving around in the generated html. AngularJS seems not to care too much about polluting the html with tags and attributes - it seems (to me in my opinion at least) to be about making reusable components and bits and making it easier to use them while coding.
I have found it's best not to use replace because then when you're inspecting your html it is harder to tell whether you've just used your directive or whether you simply put the html directly in the page. Additionally the docs mention that it's only real use case is for when you're generating SVG documents.
Let me use your example here to illustrate what I'm trying to say:
Source:
<some html />
<slider min="0" max="1000" step="1" label="foo" ng-model="slider1" value="750" />
<some other html />
Your desired result:
<some html />
<label>
text
<input min="0" max="1000" step="1" type="range" ng-model="data" value="250" class="ng-pristine ng-valid" />
</label>
<some other html />
Result with replace:
<some html />
<label min="0" max="1000" step="1" label="foo" ng-model="slider1" value="250" class="ng-isolate-scope ng-pristine ng-valid ng-binding">
text
<input min="0" max="1000" step="1" type="range" ng-model="data" value="250" class="ng-pristine ng-valid" />
</label>
<some other html />
Result without replace:
<some html />
<slider min="0" max="1000" step="1" label="foo" ng-model="slider1" value="250" class="ng-isolate-scope ng-pristine ng-valid ng-binding">
<label>
text
<input min="0" max="1000" step="1" type="range" ng-model="data" value="250" class="ng-pristine ng-valid" />
</label>
</slider>
<some other html />
I would suggest that when you're inspecting the html and you see your desired result how will you know whether you just wrote in the html or whether you used a directive. In the result without replace however the directive is explicitly named and it'll be impossible to mistake it for anything else. Also the html that gets inserted looks exactly like you expected it to without additional attributes on the label.
Of course you could use the compile function to remove the excess elements or attributes as mentioned by #frank but again I would suggest that this would still make your generated html less clear than the result without replace.
I would also just point out for future viewers of this question that the replace option of AngularJS directives is deprecated bearing this notice in the documentation: ([DEPRECATED!], will be removed in next major release - i.e. v2.0)
See documentation here: https://docs.angularjs.org/api/ng/service/$compile#-replace-deprecated-will-be-removed-in-next-major-release-i-e-v2-0-

Related

Angular 5 DOM two way binding input number and slider

I try to use a slider and input of type number at the same time. I create the objects in runtime so I would like to do it just in the DOM.
If I change the value of the slider the input gets the same value but not the other way around.
And also there is not value in the input number in the beginning.
..
*ngFor="let vk of selectedVK"
..
<div class="row">
<div class="col-md-7">
<input
type="range"
ngModel
name="slider"
#slider="ngModel"
min="0"
max="{{vk.max}}"
step="10"
value="{{vk.max/2}}"/>
</div>
<div class="col-md-5">
<input
type="number"
class="form-control"
[value]="slider.value"
max="{{vk.max}}"
min=0>
</div>
<p>{{slider.value}}</p>
</div>
You need to use two-way data binding.
With two-way data binding, when properties in the model get updated, so does the UI. When UI elements get updated, the changes get propagated back to the model.
<input
type="number"
class="form-control"
[(ngModel)]="slider.value"
max="{{vk.max}}"
min=0>

How to Create rule data in html

Create page htm include number 0~9 and rule, when you click to number or rule then data change the same image
You might be looking for something like the html range-type input, e.g. <input type="range" id="mySlider" min="0" value="5" max="9" step="1">. For example, see this description.

How to dynamically update range slider

I've created the following code to show the user their range slider value. However, it only shows the value when the user stops moving the slider. Is there a way to show the value WHILE the user drags the range slider? I'm looking for a way to do this in vanilla JS.
function updateInput(val) {
document.getElementById('textInput').innerHTML=val;
}
<input type="range" name="rangeInput" min="0" max="100" onchange="updateInput(this.value);">
<p id="textInput"></p>
Here you go:
<input type="range" name="rangeInput" min="0" max="100" onchange="updateInput(this.value);" oninput="updateInput(this.value)" >
<p id="textInput"></p>
oninput is not supported in IE10, so you have to use both, oninput and onchange.
Here is the demo
Use oninput instead of onchange.
Magical proof!
onmousemove function make this happen:
<input type="range" name="rangeInput" min="0" max="100" onmousemove="document.getElementById('textInput').innerHTML=this.value;">
<p id="textInput"></p>

Javascript calculations working in IE only

I am trying to create a form so that user can enter certain information and JavaScript will do the calculations for them. I've been trying to use http://demo.rsjoomla.com/calculation-form-example (the one on the left) to get the basics started and I can manipulate from there. So far though it's only working in IE.
Here's the basic layout of my code:
HTML
<input type="number" name="income1" value="0" onkeyup="update()">
<input type="number" name="income2" value="0" onkeyup="update()">
<input type="number" name="income3" value="0" onkeyup="update()">
JavaScript
var op1=document.getElementById('income1');
var op2=document.getElementById('income2');
var result=document.getElementById('income3');
if(op1.value=="" || op1.value!=parseFloat(op1.value)) op1.value=0;
if(op2.value=="" || op2.value!=parseFloat(op2.value)) op2.value=0;
result.value=0;
result.value=parseInt(result.value);
result.value=parseInt(result.value)+parseInt(op1.value) - parseInt(op2.value);
You wrote code that is looking for id
document.getElementById('income1');
Where is the id on the input?
<input type="number" name="income1" value="0" onkeyup="update()">
Name is not the same thing as id.
And your parseFloat check, you probably should look at isNaN(). And you are using parseInt() at the bottom, and you are using parseFloat() above!
If you're going to do getElementById, you need to have an ID in your element.
<input type="number" id="income1" value="0" onkeyup="update()">
var op1=document.getElementById('income1');
Or you could use jQuery (requires including jQuery source):
<input type="number" name="income1" value="0" onkeyup="update()">
var op1 = ${"input[name=income1]").val();
Alternatively, you could do this, assuming you only have one element named income1. This isn't a very good way to do this, but it should work.
<input type="number" name="income1" value="0" onkeyup="update()">
var op1=document.getElementsByName('income1')[0];

range input disable does not work in chrome

I am disabling my range input however in chrome it shows it grayed out but it is still usable.
<input type="range" disabled min="0" max="100"/>
I would assume the above would not allow you to change its value.
Am I doing it wrong?
jsFiddle
Relevant specification Disabled
Here is the Chrome bug report, guess just need to wait for version 15 as the commenters mentioned.
Bug 54820
you can remove all binded events of that specific scroll group to make that scroll disable like:
<div id="fieldset1">
<input type="range" disabled min="0" max="100" readonly="1"/>
</div>
<script>
$(":range").rangeinput();
$('#fieldset1 *').unbind(); // for all events
</script>
its works ..
no need to disable text field; beacause on form submission that field will not be posted ..
My solution JSFIDDLE (Works fine in default android browser)
html
<input id="range" type="range" value="10" min="0" max="30" step="10"/>
<button id="disableBtn">Disable</button>
JS
document.getElementById('disableBtn').addEventListener('input', filter);
document.getElementById('disableBtn').addEventListener('click', disable);
function disable(){
document.getElementById('range').disabled = !document.getElementById('range').disabled;
}
function filter(){
if(document.getElementById('range').disabled){
document.getElementById('range').value = document.getElementById('range').defaultValue;
}
}
I found a corny solution for chrome, because it doesn't seem like you can disable it from user input. Put a div over it so a user cannot interact with it. Not pretty but works:
<div style="position:relative;">
<div style="position:absolute;z-index:5;width:100%;height:100%;"></div>
<input type="range" disbaled=True min="0" max="100" value="0"/><span id="v">100</span>
</div>

Categories