I'm trying to be real fancy with angular inputs by using both ng-pattern and ng-model parsing together. The regex I put in ng-pattern works fine on regex101.com, and even logging it in my app it works great. When using it in ng-pattern however, its saying my input is invalid though when it should not be. I'm wondering when ng-pattern does its thing in relation to when ngModel.$parsers/ngModel.$formatters are doing their thing, because i could see that causing it to fail. Here's some code:
Here's the ngModel parsing directive:
UI.directive('formatSeconds', function() {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, element, attrs, ngModel) {
var padZero = function (num, size) {
return ('00' + num).substr(-size);
};
var formatSeconds = function (seconds) {
var min = Math.floor(seconds / 60);
var sec = Math.floor(seconds % 60);
var ms = Math.round(((seconds % 60) - sec) * 1000);
return min + ':' + padZero(sec, 2) + ':' + padZero(ms, 3);
};
var parseTime = function (time) {
time = time.split(':');
var min = parseInt(time[0] || 0);
var sec = parseInt(time[1] || 0);
var ms = parseInt(time[2] || 0);
return min * 60 + sec + (ms / 1000);
};
ngModel.$parsers.push(parseTime);
ngModel.$formatters.push(formatSeconds);
}
};
});
Here's my regex in my controller:
$scope.timeRegex = /^([0-9]+)?\:([0-5][0-9])\:?([0-9]{3})?$/;
And here's the relevant part of my view:
<tbody ng-form name="syncForm">
<tr class="timing-entry" ng-repeat="entry in scenario.syncManifest">
<td>
<input type="text" ng-attr-name="{{'time' + $index}}" required ng-model="entry.time" format-seconds ng-pattern="timeRegex" />
</td>
</tr>
</tbody>
The time in entry is in seconds, so the formatter puts it in 0:00:000 format. Then I hoped the ng-pattern would kick in and say yes! valid! But I'm wondering if it is running when the time property is still in 0.000 format before parsing.
Angular validation is performed upon the ng-model value, that is to say:
When a value is inputted into the view, the $parsers will run and the inputted value will be transformed into how you want it stored in the ng-model. In this case, thats a number representing the number of seconds. Then the ng-pattern will work on that value - if it passes validation, ng-model will be set.
When the value is set from the controller, the ng-pattern will go to work on that raw ng-model value. I believe the $formatters will run and the formatted $viewValue will be sent to the view regardless of the validation result.
Either way - in your example, ng-pattern will be working on the integer value of seconds, not the formatted value displayed in the control.
Related
I'm trying to make a script that will find the width of an item and check if the selected item width is the same and then show an alert.
For some reason my if condition is not working even when all the conditions are met.
Here is my code:
var doc = app.activeDocument;
function mm(n) {return n / 2.83464566929134;}
function pt(n) {return n * 2.83464566929134;}
//=====================
// Calculate Prisa
//=====================
var prisa = doc.pathItems.getByName("prisa");
var prisawidth = mm(prisa.geometricBounds[2]-prisa.geometricBounds[0]);
//=========================
// Calculate Selection
//=========================
var sel = doc.selection[0];
var selwidth = mm(sel.geometricBounds[2]-sel.geometricBounds[0]);
if (selwidth == prisawidth) {alert("Same Width");}
You can try this:
if (Math.abs(selwidth - prisawidth) < .01) alert("About the same width");
I think the problem has to do with rounding of the numbers. Say, you can see '2 mm' and '2 mm', but actually there are '2.00001 mm' and '2.00002 mm' or something like this. So it's need either to round the fugures before compairing or check if the diffference is less than some minimal value.
Good afternoon all,
I'm trying to call all of the results within an API that has:
6640 total records
100 records per page
67 pages of results (total records / records per page)
This is an ever growing list so I've used variables to create the above values.
I can obviously use the $Skip ODATA expression to get any one of the 67 pages by adding the expression to the end of the URL like so (which would skip the first 100, therefore returning the 2nd page:
https://psa.pulseway.com/api/servicedesk/tickets/?$Skip=100
What I'm trying to do though is to create a custom function that will loop through each of the 67 calls, changing the $Skip value by an increment of 100 each time.
I thought I'd accomplished the goal with the below code:
let
Token = "Token",
BaseURL = "https://psa.pulseway.com/api/",
Path = "servicedesk/tickets/",
RecordsPerPage = 100,
CountTickets = Json.Document(Web.Contents(BaseURL,[Headers = [Authorization="Bearer " & Token],RelativePath = Path & "count"])),
TotalRecords = CountTickets[TotalRecords],
GetJson = (Url) =>
let Options = [Headers=[ #"Authorization" = "Bearer " & Token ]],
RawData = Web.Contents(Url, Options),
Json = Json.Document(RawData)
in Json,
GetPage = (Index) =>
let Skip = "$Skip=" & Text.From(Index * RecordsPerPage),
URL = BaseURL & Path & "?" & Skip,
Json = GetJson(URL)
in Json,
TotalPages = Number.RoundUp(TotalRecords / RecordsPerPage),
PageIndicies = {0.. TotalPages - 1},
Pages = List.Transform(PageIndicies, each GetPage(_))
in
Pages
I got all happy when it successfully made the 67 API calls and combined the results into a list for me to load in to a Power Query table, however what I'm actually seeing is the first 100 records repeated 67 times.
That tells me that my GetPage custom function which handles the $Skip value isn't changing and is stuck on the first one. To make sure the Skip index was generating them properly I duplicated the query and changed the code to load in the $Skip values and see what they are, expecting them all to be $Skip=0, what I see though is the correct $Skip values as below:
Image showing correct Skip values
It seems everything is working as it should be, only I'm only getting the first page 67 times.
I've made a couple of posts on other community site around this issue before but I realise the problem I was (poorly) describing was far too broad to get any meaningful assistance. I think now I've gotten to the point where I understand what my own code is doing and have really zoomed in to the problem - I just don't know how to fix it when I'm at the final hurdle...
Any help/advice would be massively appreciated. Thank you.
Edit: Updated following #RicardoDiaz answer.
let
// Define base parameters
Filter = "",
Path = "servicedesk/tickets/",
URL = "https://psa.pulseway.com/api/",
Token = "Token",
Limit = "100",
// Build the table based on record start and any filters
GetEntityRaw = (Filter as any, RecordStart as text, Path as text) =>
let
Options = [Headers=[ #"Authorization" = "Bearer " & Token ]],
URLbase = URL & Path & "?bearer=" & Token & "&start=" & RecordStart & "&limit=" & Text.From(Limit),
URLentity = if Filter <> null then URLbase & Filter else URLbase,
Source = Json.Document(Web.Contents(URLentity, Options)),
Result = Source[Result],
toTable = Table.FromList(Result, Splitter.SplitByNothing(), null, null, ExtraValues.Error)
in
toTable,
// Recursively call the build table function
GetEntity = (optional RecordStart as text) as table =>
let
result = GetEntityRaw(Filter, RecordStart, Path),
nextStart = Text.From(Number.From(RecordStart) + Limit),
nextTable = Table.Combine({result, #GetEntity(nextStart)}),
check = try nextTable otherwise result
in
check,
resultTable = GetEntity("0")
in
resultTable
As I couldn't test your code, it's kind of hard to provide you a concrete answer.
Said that, please review the generic code I use to connect to an api and see if you can find where yours is not working
EDIT: Changed api_record_limit type to number (removed the quotation marks)
let
// Define base parameters
api_url_filter = "",
api_entity = "servicedesk/tickets/",
api_url = "https://psa.pulseway.com/api/",
api_token = "Token",
api_record_limit = 500,
// Build the table based on record start and any filters
fx_api_get_entity_raw = (api_url_filter as any, api_record_start as text, api_entity as text) =>
let
api_url_base = api_url & api_entity & "?api_token=" & api_token & "&start=" & api_record_start & "&limit=" & Text.From(api_record_limit),
api_url_entity = if api_url_filter <> null then api_url_base & api_url_filter else api_url_base,
Source = Json.Document(Web.Contents(api_url_entity)),
data = Source[data],
toTable = Table.FromList(data, Splitter.SplitByNothing(), null, null, ExtraValues.Error)
in
toTable,
// Recursively call the build table function
fxGetEntity = (optional api_record_start as text) as table =>
let
result = fx_api_get_entity_raw(api_url_filter, api_record_start, api_entity),
nextStart = Text.From(Number.From(api_record_start) + api_record_limit),
nextTable = Table.Combine({result, #fxGetEntity(nextStart)}),
check = try nextTable otherwise result
in
check,
resultTable = fxGetEntity("0"),
expandColumn = Table.ExpandRecordColumn(
resultTable,
"Column1",
Record.FieldNames(resultTable{0}[Column1]),
List.Transform(Record.FieldNames(resultTable{0}[Column1]), each _)
)
in
expandColumn
QUESTION TO OP:
Regarding this line:
Result = Source[Result],
Does the json return a field called result instead of data?
I'm trying to use Chart.js with a datetime x axis, and I need to adjust all my values by subtracting 5 hours. Here's some of my code:
var timeFormat = 'MM/DD HH:mm';
time: {
format: timeFormat,
tooltipFormat: 'll',
parser: function(utcMoment) {
return moment(utcMoment).utcOffset(5, true);
}
},
Without the parser function, my values are normal (10:00, January 10, 2021), but with the parser function, for some reason my values are set back all the way to 2001. Yes two-thousand-and-one.(10:00, January 10, 2001) Note that the time is not actually changed (So two errors: 1.time not adjusted when it should be. 2:years adjusted when it shouldn't be). Why could this be?
I will assume that the reason you want to roll it back by 5 hours is because of a timezone difference. If that's the case, you should use moment-timezone instead of moment.
With that said, subtracting 5 hours from the current date is actually simpler than what you're doing.
Before feeding a date into moment, you need to convert it to the js Date object like so: new Date('2021-01-10 00:00:00'). Since your parser function accepts the date in m/d H:M format, you would need to append the year to it first.
So here is how your code should look:
parser: function(utcMoment) {
const new_date = utcMoment.split(' ')[0] + '/' + (new Date().getFullYear()) + ' ' + utcMoment.split(' ')[1];
return moment(new Date(new_date)).subtract({hours: 5})
}
I have a map reduce view:
.....
emit( diffYears, doc.xyz );
reduced with _sum.
xyz is then a number which is summed per integer(diffYears).
The output looks roughly like this:
4 1204.9
5 796.19
6 1124.8
7 1112.6
8 1993.62
9 159.26
10 395.41
11 456.05
12 457.97
13 39.80
14 483.68
15 269.469
etc..
What I would like to do is group the results as follows:
Grouping Total per group
0-4 1959.2 i.e add up the xyz's for years 0,1,2,3,4
5-9 3998.5 same for 5,6,7,8,9 ...etc.
10-14 3566.3
I saw a suggestion where a list was used on a view output here: Using a CouchDB view, can I count groups and filter by key range at the same time?
but have been unable to adapt it to get any kind of result.
The code given is:
{
_id: "_design/authors",
views: {
authors_by_date: {
map: function(doc) {
emit(doc.date, doc.author);
}
}
},
lists: {
count_occurrences: function(head, req) {
start({ headers: { "Content-Type": "application/json" }});
var result = {};
var row;
while(row = getRow()) {
var val = row.value;
if(result[val]) result[val]++;
else result[val] = 1;
}
return result;
}
}
}
I substituted var val = row.key in this section:
while(row = getRow()) {
var val = row.value;
if(result[val]) result[val]++;
else result[val] = 1;
}
(although in this case the result is a count.)
This seems to be the way to do it.
(It is like having a startkey and endkey for each grouping which I can do manually, naturally, but not inside a process. Or is there a way of entering multiple start- and endkeys into one GET command???? )
This must be a fairly normal thing to do especially for researchers using statistical analysis.
I assume therefore that it does get done but I cannot locate examples
as far as CouchDB is concerned.
I would appreciate some help with this please or a pointer in the right direction.
Many thanks.
EDIT:
Perhaps the answer lies in a process in 'reduce' to group the output??
You can accomplish what you want using a complex key. The limitation is that the group size is static and needs to be defined in the view.
You'll need a simple step function to create your groups within map like:
var size = 5;
var group = ( doc.diffYears - (doc.diffYears % size)) / size;
emit( [group, doc.diffYears], doc.xyz);
The reduce function can remain _sum.
Now when you query the view use group_level to control the grouping. At group_level=0, everything will be summed and one value will be returned. At group_level=1 you'll receive your desired sums of 0-4, 5-9 etc. At group_level=2 you'll get your original output.
In ColdFusion I can see the code below, however it does not seem to work. I want to make sure discount is only applied if the valid from and to dates are in range, see below.
if (
DATEDIFF("d", discount.ValidFrom(), now()) >= 0
AND
DATEDIFF("d", now(), discount.ValidTo()) <= 0
){
// ALL OK Accept Discount
}
else
{
// Discount is no Longer Valid boo!
}
Try this:
Today = Int(Now());
if ( Today GTE Int(discount.ValidFrom())
AND Today LTE Int(discount.ValidTo())
)
{
// discount is valid
}
else
{
// no longer valid
}
It works because datetimes are basically just numbers - with the integer/whole part being the days and the decimal/fraction part being the time.
So applying the Int function will convert a datetime to a whole day date, and then you can just do a simple numeric comparison to ensure it is within the ranges.
I find this far more readable and understandable than the DateDiff stuff - there's no confusion over the ordering of things, which I think is the problem with your provided code snippet (you've switched both order and lte/gte; you only wanted to change one or the other).
Your logic is a bit off. Right now you're returning
if ({positive_number} and {negative_number})
which returns false. You should be checking if dateDiff("d", today, discount.to()) is also >= 0.
<cfscript>
local = {};
local.start = createDate( 2011, 10, 01 );
local.end = createDate( 2011, 10, 30 );
local.today = now();
local.valid = false;
if ( (dateDiff("d", local.start, local.today) >= 0)
AND (dateDiff("d", local.today, local.end) >= 0) ){
local.valid = true;
}
</cfscript>
<cfoutput>
x < z: #dateDiff("d", local.start, local.today) GTE 0#
<hr />
z < y: #dateDiff("d", local.today, local.end) GTE 0#
<hr />
Valid: #local.valid#
</cfoutput>