I'm listing out several inputs based on another input like this like this:
<span ng-repeat="_ in ((_ = []) && (_.length=assistant.bends || 0) && _) track by $index" class="bendsInput">
#{{$index+1}} <br>
<input type="text" placeholder="ft" ng-change="calculateLength()"> ft
<input type="text" placeholder="in" ng-change="calculateLength()"> in
</span>
NOTE: the ng-repeat section might be really confusing, basically it's an ng-repeat between 0 and whatever the value of assistant.bends is the $index variable is the current index of the loop.
I need to add an ng-model to both the ft and in textboxes so that I can access them (the value of assistant.bends is dynamic and not fixed.
I'm thinking something like this: ng-model="assistant.bend{{$index}}.ft"
So that the final result will be ng-model="assistant.bend1.ft"
Then in my javascript I can loop through it and add all the feet and inches together.
var totalFeet = 0;
for(i=0; i<assistant.bends; i++) {
totalFeet += assistant.bend+i+.ft;
}
I'm not sure on the correct syntax for something like this.
Some advice on dynamic models: If you need a complex structure, use one, rather than repeating for a number of times based on a number
Ex:
// your JS needs a more complex structure
$scope.assistant = {
// bends: 5 // not great, you can use this value to generate objects such as below
bends: [ {ft: '', in: ''}, {ft: '', in: ''}, {ft: '', in: ''} ]
}
// if bends value changes, update the array
HTML
<span ng-repeat="bend in assistant.bends track by $index" class="bendsInput">
#{{$index+1}} <br>
<input type="text" placeholder="ft" ng-model="bend.ft" ng-change="calculateLength()"> ft
<input type="text" placeholder="in" ng-model="bend.in" ng-change="calculateLength()"> in
</span>
<div class='sum' ng-bind="totalFeet"></div> <!-- this will update each time your function for summation runs -->
This way, your ng-model gets assigned to whatever attribute is on the structure. You can even create new keys dynamically, though I don't recommend it for the sake of consistency.
Then your loop can be about the same:
$scope.totalFeet = 0, totalInches = 0;
for(i=0; i<$scope.assistant.bends.length; i++) {
$scope.totalFeet += assistant.bends[i].ft;
totalInches += assistant.bends[i].in;
}
$scope.totalFeet += (totalInches / 12);
Related
https://datatables.net/reference/api/search()#Example
Im using the link above as an example for my searching, but my setup is quite different.
<td>
<div class="plCell_desktop">
<input type="radio" class="" data-lnk_id="414107671" data-group="RUTH">
<label for="414107671">RUTH</label>
</div>
</td>
here is a extract from my table.
The only visable bit of data is "Ruth".
but when I search for say '76' it will still bring "Ruth" back as a result.
The reason is most likely the fact that I have a lot more info in the table cell than "Ruth".
Okay, so my question is. Can you force DataTables to search from the beginning of a word. e.g. ( enter "uth" will not bring back "Ruth", but "Ru" will, hope it makes sense ).
Can you do a kind of "innerHTML.val()" search with DataTables?
Okay, so my question is. Can you force DataTables to search from the
beginning of a word. e.g. ( enter "uth" will not bring back "Ruth",
but "Ru" will, hope it makes sense ).
Yes. Create a custom filter upfront that perform filtering like this. The default "smart search" will be overruled by the custom filter and any future filtering will go through that :
$.fn.dataTable.ext.search.push(function( settings, data, dataIndex ) {
var term = $('.dataTables_filter input').val().toLowerCase()
for (var i=0, l=data.length; i<l; i++) {
if (data[i].toLowerCase().indexOf(term) == 0 ) return true
}
return false
})
demo -> http://jsfiddle.net/qxcjzuxa/
As you may notice it would be very easy to make the dataTables filtering overall case sensitive (just an example). The filter array is a LIFO-structure where you can have multiple filters on top of each other. You remove a filter simply by $.fn.dataTable.ext.search.pop() if you for any reason will disable "beginning of word" filtering dynamically.
Could you just use jQuery?
$(".plCell_desktop label").each(function() {
// Using RexExp matching
RexExp regex = new RegExp(); // Your regex obj
if ($(this).val().match(regex)) {
// Do stuff if it matches
}
// Or if you just want to do something if it has a value:
if ($(this).val()) {
// ...
}
});
If you need to access the matching labels many times in your code, you may want to avoid computing the regular expression each time. One solution would be to run a one-time pre-processing that would add a custom attribute. Let's call it isOk.
You then can select the labels with a standard jQuery selector:
$('label[isOk=Y]')
Below is some demo code.
var regex = /^RU/;
$('label').each(function() {
$(this).attr('isOk', $(this).html().match(regex) !== null ? 'Y' : 'N');
});
var res = $('label[isOk=Y]');
// check whether we've selected the correct labels
res.each(function() { console.log($(this).attr('for')); });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<td>
<div class="plCell_desktop">
<input type="radio" class="" data-lnk_id="414107671" data-group="RUTH">
<label for="414107671">RUTH</label>
<input type="radio" class="" data-lnk_id="414107672" data-group="RUTH">
<label for="414107672">RUTH TOO</label>
<input type="radio" class="" data-lnk_id="414107673" data-group="RUTH">
<label for="414107673">NOT REALLY RUTH</label>
</div>
</td>
My page shows some forms with content loaded from a database. Every row will get his own <input>. The ID of this input is equal for every row, except for the number that is attached to it, to make it unique. To make it more clear; this is how the form looks like when it loads 3 rows from the database:
<form>
<input id="Amount1" value="<?php echo $databaseValue; ?>" >
<input id="Amount2" value="<?php echo $databaseValue; ?>" >
<input id="Amount3" value="<?php echo $databaseValue; ?>" >
<input type="hidden" name="numberOfRows">
<input id="finalResult">
</form>
This is all done with the mysqli_array function. The value of numberOfRows is based on numRows function.
What I'd like to achieve is that javascript calculates the value of each existing input and put the result in finalResult, regardless the number of forms (because this may vary). If I make some changes to one of the values, the finalResult should update real-time.
What I've tried so far:
formnum contains the number of fields.
var a is created at the beginning, starting at 0. Inside it's function I create an ID, matching the fields on the page. All fields are named "Amount" + number. If this number equals the number of fields, the function will stop. This way the script won't be looking for fields that doesn't excist.
Then it gets the value of this field and adds the value to var b. var b is just created to store the value temporary, untill the function's over.
At the end the total is divided to 15. This is something extra I need. Nothing special on this line.
My code:
<script type='text/javascript'>
$(document).ready(function(){
var formnum = $("#numberOfRows").val();
var a;
var b = 0;
var formname = '#Amount';
for (a = 0; a < formnum; a++) {
var complete = formname.concat(a);
var completeContent = $(complete).val();
b = b + completeContent;
};
b = b.toFixed(2);
});
$(document).mousemove(function(event){
var formula_finalResult = b / 15;
var total_finalResult = Math.floor(formula_finalResult);
$("#finalResult").val(total_finalResult);
});
</script>
This doesn't do anything. It doesn't change the value. What's going wrong?
Make it simple:
$(function(){
var sum = 0;
// Selector to select all input whose id starts with Amount
$("input[id*='Amount']").each(function(){
sum += +$(this).val(); // Parsing as int and adding it to sum
});
$("#finalResult").val(Math.floor(sum/15)); // Storing the values
})
Assuming that all of the fields always have Amount at the beginning of their id attribute, you could use jQuery's ID selector to achieve this, without the need for any of the internal counters, etc.
I'm not entirely sure why you need to hook into the mousemove event, since the data should never change on the page (since it's being generated by PHP when the page is first loaded). The following code should achieve what you're looking for:
$(function() {
var total = 0;
$('input[id*="Amount"]').each(function() { total+= parseFloat( $(this).val() ); });
$('#finalResult').val( Math.floor( total / 15 ) );
});
Your code has an error Uncaught ReferenceError: b is not defined
see it in action here: http://jsfiddle.net/ca9vascj/
There's no reason to bring the mousemove event into this, I'm not even sure what that was needed for.
Like the above answers, here's a much simplified version. But instead of a partial ID selection, let's just give the form an ID, and then give all the needed elements inside that form a class that we can select by. We also no longer need to have the numberOfRows form element.
<form id="theForm">
<input class="formAmmount" value="5" />
<input class="formAmmount" value="10" />
<input class="formAmmount" value="27.5" />
<input class="formAmmount" value="4" />
<input class="formAmmount" value="9" />
<hr />
<input id="finalResult" />
</form>
And then our jQuery code can be reduced to this:
$(function(){
var total = 0;
$("#theForm .formAmmount").each(function(){
total += parseFloat(this.value, 10);
});
var final = Math.floor(total.toFixed(2) / 15);
$("#finalResult").val(final);
});
See it in action here: http://jsfiddle.net/ca9vascj/1/
You dont'need jQuery. The simplest way to do this is document.getElementsByTagName:
var inputs = document.getElementById('my-form').getElementsByTagName('input')
That's it. inputs.length will always get an actual count of inputs in your form. That's because getElementsByTagName() returns a NodeList object, containing a live view of the matching elements. This object is mutable; it will change in response to DOM mutations.
So if you need to get sum from all of the inputs:
function sum() {
var result = 0;
[].slice.call(inputs).forEach(function(input){
result += parseFloat(input.value)
});
return result;
}
If you are able to change the generated Html-Source I would suggest to give a new class to your InputElements.
<input id="Amount1" class="ElementToCount" value="<?php echo $databaseValue; ?>" >
Then you can calculate like that
var getSumOfElements = function() {
var Elements = $('.ElementToCount')
var sum=0
if (Elements && Elements.length>0) {
for (var i=0; i<Elements.length; i++) {
sum += Elements[i].val();
}
}
return sum
}
And to update the field you could register to the 'change'-Event
$('.ElementToCount).on('change', function() {
$('#finalResult').val(getSumOfElements());
})
I am new to AngularJS. In my scenario, the user has to create a mcq question. The question has 4 default option and one of the options is correct. Now the user who is teacher can give greater or less then 4 options for the question. So its a variable number of options. If hard code the input as follow
<input name = "input0" type = "text", class = "form-control" ng-model = "input_0" required>
<input name = "input1" type = "text", class = "form-control" ng-model = "input_1" required>
and so on it works good. I want to use dynamic solution here, so it does not matter how many options the teacher provide.
What I was trying to do is
$scope.mcq_options = [$scope.input_0,$scope.input_1 ...]
use ng-repeat in html template and do something like
<div ng-repeat = "input in mcq_options">
<input name = "input1" type = "text", class = "form-control" ng-model = "input" required>
For removing splice entry from array
For adding more push entry in array
The solution is quite straightforward (Associated PLUNKER):
1 Create an empty array that you may store all your options, in your controller.
var inputArray = $scope.inputArray = [];
[2] Create a function to add new options.
$scope.addNewOption = function() {
inputArray.push('');
};
[3] Create another function to splice an option entry that accepts the index of an option to remove.
$scope.removeOption = function(index) {
inputArray.splice(index, 1);
};
[4] Your view can be something like this:
<form name="form" novalidate>
<div ng-repeat="input in inputArray track by $index" ng-form="subform">
<input name="input" type="text" ng-model="inputArray[$index]" required> <button ng-click="removeOption($index)">Remove</button>
<br>
<span ng-show="subform.input.$error.required">This field is rqeuired</span>
</div>
<button ng-click="addNewOption()">Add New Option</button>
</form>
Note:
The track by $index in the ng-repeat directive helps in avoiding duplicate values error.
The ng-form directive helps you in validating each models that is created in every ng-repeat iteration.
Instead of using the input value in the ng-repeat directive, use its direct reference by using the ng-repeat's $index property. If you dont't do this, changes in the inputArray may affect the current ngModel reference of your inputs. e.g. adding or removing options will give you weird behaviours.
function ProvideValue(){
Values = document.getElementById('HiddenValue').value;
FirstCut = Values.split("###"); // This will return the array ID#-#VALUE#-#TYPE
var CtrlId;
for (i = 0; i < FirstCut.length - 1; i++) {
Strings = FirstCut[i];
SecondCut = Strings.split("#-#");
if(SecondCut[2].match("TEXT")) {
CtrlId = "" + SecondCut[0];
document.getElementById(CtrlId).value = SecondCut[1];
}
}
}
This is my code instead of the Id, which i can print it.But CtrlId is not replaced by the actual value. Am getting error document.getElementById(CtrlId).value is NULL. I tried to hard code the ID then its working fine but i cannot hard code the controlsID because there are 1000s of control and everytime the ID changes.
Your code seems fine (apart from implied globals1), you must have some other problem in your HTML document... I'm also not sure why you're leaving out the last value from the first cut since you're interating to length - 2, because i is less than length - 1 (not less than or equal) which means that it goes all the way to value length - 2 and then breaks the loop.
Here's a JSFiddle I created that uses your code and displays some additional console messages and actually applies values to inputs as provided by the hidden input.
1Important
I applied var to your variables so they're not implied globals which should be avoided at all times because they're nothing but evil friend of hidden bugs.
The code I used
HTML is super simple but I do have both elements with IDs that are being addressed in the compound value of the hidden field:
<input type="hidden" id="hidden" value="me#-#Rob#-#text###you#-#Mike#-#text" />
<input id="me" value="name" />
<input id="you" value="name" />
Script is simple as well (runs on DOM ready for JSFiddle simplicity reasons):
var vals = document.getElementById('hidden').value;
var firstCut = vals.split("###");
for(var i = 0; i < firstCut.length; i++) {
var ctrl = firstCut[i].split("#-#");
if (ctrl[2].match("text")) {
var id = ctrl[0];
document.getElementById(id).value = ctrl[1];
}
}
I am using ASP.Net MVC along with Jquery to create a page which contains a contact details section which will allow the user to enter different contact details:
<div id='ContactDetails'>
<div class='ContactDetailsEntry'>
<select id="venue_ContactLink_ContactDatas[0]_Type" name="venue.ContactLink.ContactDatas[0].Type">
<option>Email</option>
<option>Phone</option>
<option>Fax</option>
</select>
<input id="venue_ContactLink_ContactDatas[0]_Data" name="venue.ContactLink.ContactDatas[0].Data" type="text" value="" />
</div>
</div>
<p>
<input type="submit" name="SubmitButton" value="AddContact" id='addContact' />
</p>
Pressing the button is supposed to add a templated version of the ContactDetailsEntry classed div to the page. However I also need to ensure that the index of each id is incremented.
I have managed to do this with the following function which is triggered on the click of the button:
function addContactDetails() {
var len = $('#ContactDetails').length;
var content = "<div class='ContactDetailsEntry'>";
content += "<select id='venue_ContactLink_ContactDatas[" + len + "]_Type' name='venue.ContactLink.ContactDatas[" + len + "].Type'><option>Email</option>";
content += "<option>Phone</option>";
content += "<option>Fax</option>";
content += "</select>";
content += "<input id='venue_ContactLink_ContactDatas[" + len + "]_Data' name='venue.ContactLink.ContactDatas[" + len + "].Data' type='text' value='' />";
content += "</div>";
$('#ContactDetails').append(content);
}
This works fine, however if I change the html, I need to change it in two places.
I have considered using clone() to do this but have three problems:
EDIT: I have found answers to questions as shown below:
(is a general problem which I cannot find an answer to) how do I create a selector for the ids which include angled brackets, since jquery uses these for a attribute selector.
EDIT: Answer use \ to escape the brackets i.e. $('#id\\[0\\]')
how do I change the ids within the tree.
EDIT: I have created a function as follows:
function updateAttributes(clone, count) {
var f = clone.find('*').andSelf();
f.each(function (i) {
var s = $(this).attr("id");
if (s != null && s != "") {
s = s.replace(/([^\[]+)\[0\]/, "$1[" + count + "]");
$(this).attr("id", s);
}
});
This appears to work when called with the cloned set and the count of existing versions of that set. It is not ideal as I need to perform the same for name and for attributes. I shall continue to work on this and add an answer when I have one. I'd appreciate any further comments on how I might improve this to be generic for all tags and attributes which asp.net MVC might create.
how do I clone from a template i.e. not from an active fieldset which has data already entered, or return fields to their default values on the cloned set.
You could just name the input field the same for all entries, make the select an input combo and give that a consistent name, so revising your code:
<div id='ContactDetails'>
<div class='ContactDetailsEntry'>
<select id="venue_ContactLink_ContactDatas_Type" name="venue_ContactLink_ContactDatas_Type"><option>Email</option>
<option>Phone</option>
<option>Fax</option>
</select>
<input id="venue_ContactLink_ContactDatas_Data" name="venue_ContactLink_ContactDatas_Data" type="text" value="" />
</div>
</div>
<p>
<input type="submit" name="SubmitButton" value="AddContact" id='addContact'/>
</p>
I'd probably use the Javascript to create the first entry on page ready and then there's only 1 place to revise the HTML.
When you submit, you get two arrays name "venue_ContactLink_ContactDatas_Type" and "venue_ContactLink_ContactDatas_Data" with matching indicies for the contact pairs, i.e.
venue_ContactLink_ContactDatas_Type[0], venue_ContactLink_ContactDatas_Data[0]
venue_ContactLink_ContactDatas_Type[1], venue_ContactLink_ContactDatas_Data[1]
...
venue_ContactLink_ContactDatas_Type[*n*], venue_ContactLink_ContactDatas_Data[*n*]
Hope that's clear.
So, I have a solution which works in my case, but would need some adjustment if other element types are included, or if other attributes are set by with an index included.
I'll answer my questions in turn:
To select an element which includes square brackets in it's attributes escape the square brackets using double back slashes as follows: var clone = $("#contactFields\[0\]").clone();
& 3. Changing the ids in the tree I have implemented with the following function, where clone is the variable clone (in 1) and count is the count of cloned statements.
function updateAttributes(clone, count) {
var attribute = ['id', 'for', 'name'];
var f = clone.find('*').andSelf();
f.each(function(i){
var tag = $(this);
$.each(attribute, function(i, val){
var s = tag.attr(val);
if (s!=null&& s!="")
{
s = s.replace(/([^\[]+)\[0\]/, "$1["+count+"]");
tag.attr(val, s);
}
});
if ($(this)[0].nodeName == 'SELECT')
{ $(this).val(0);}
else
{
$(this).val("");
}
});
}
This may not be the most efficient way or the best, but it does work in my cases I have used it in. The attributes array could be extended if required, and further elements would need to be included in the defaulting action at the end, e.g. for checkboxes.