Update countdown variable on Angular Timer - angularjs

I am using Angular Timer http://siddii.github.io/angular-timer/examples.html#/angularjs-single-timer
But I can't update the countdown variable. I see that I'm not the only one having this issue. I tried some "solutions" but this didn't work. What is the best way to make it work? Don't want to make a new countdown because this timer directive has a lot of features that I need. It's just that I can't update the countdown from a controller.
I have a select updating content which works perfect, except for the timer, I've added different time values
$scope.typeWods = [
{ label: 'EMOM', value: 1, time: 500 },
{ label: 'TABATA', value: 2, time: 900 },
{ label: 'POR VUELTAS', value: 3, time: 800 },
{ label: 'AMRAP', value: 4, time: 1200 },
{ label: '21-15-9', value: 5, time: 700 }
];
The variable is updated, but the countdown property is not. Any good solution out there? Don't know what else to try.

angular-timer requires momentjs and humanize-duration libraries.
This is mentioned at - https://github.com/siddii/angular-timer#requirements
Updated plnkr: http://plnkr.co/edit/OkqS8fyZCiegsUjIW13L?p=preview

So i resolved this with Vinay K answer but instead of using timer-set-countdown i used timer-set-countdown-seconds to update the countdown and work perfect!
$scope.$broadcast('timer-set-countdown-seconds', $scope.variable);
$scope.$on('timer-set-countdown-seconds', function (e, seconds) {
console.log(seconds);
});

Related

Enable all range selector's options in stock highcharts

In range-selector, I have many options to select from (in reality) and in given demo, I initially load last 2 hours data.
In this scenario, last 1 hour option is enabled but other options are disabled.
I really don't know what is wrong. The requirement is to load last 2 hour data first and then from dropdown, you can select other options (eg. last 6 hours) and accordingly data will be loaded.
How to enable other options in range-selector ?
I tried setting
minRange:1
but I have no clue how to fix it.
DEMO : https://stackblitz.com/edit/js-2eyktg?file=index.js,chartOptions.js,mock-data%2Fi.js
Updates:
I tried using
allButtonsEnabled: true,
It enables all options but when I click on 3 hours, 6 hours options, it doesn't make any BE call. I believed that it should automatically call afterSetExtremes functions with min & max value, fetch data from BE and update the chart but it doesn't happen.
DEMO : https://stackblitz.com/edit/js-jsxchg?file=index.js,chartOptions.js,backend.js
You can:
a) Set min property for an x-axis in a navigator:
navigator: {
xAxis: {
min: currentTimestamp - 6 * 60 * 60 * 1000, // 6 hours
},
// adaptToUpdatedData: false,
...
}
Live example: https://stackblitz.com/edit/js-m38td3?file=index.js
API Reference: https://api.highcharts.com/highstock/navigator.xAxis
b) Enable rangeSelector.allButtonsEnabled property and use afterBtnClick Highcharts event. The event afterSetExtremes is not called if the extremes are the same as the current one (they are because of initial min and max restriction).
chart: {
zoomType: 'x',
events: {
load: function() {
Highcharts.addEvent(
this.rangeSelector,
'afterBtnClick',
function() {
const button = this.buttonOptions[this.selected];
const chart = this.chart;
afterSetExtremes({
target: {
chart
},
min: chart.xAxis[0].dataMax - button._range,
max: chart.xAxis[0].dataMax
});
});
}
}
}
Live demo: https://stackblitz.com/edit/js-tuzuuz?file=chartOptions.js,index.js,index.html
Docs: https://www.highcharts.com/docs/extending-highcharts/extending-highcharts

How to animate dynamic updates in CanvasJS using React functional components?

Using React functional components, I have not been able to find a way to animate my chart with dynamic data received asynchronously. The sandbox below illustrates the problem with a timer simulating the asynchronous read.
https://codesandbox.io/s/basic-column-chart-in-react-canvasjs-0gfv6?fontsize=14&hidenavigation=1&theme=dark
When running the example code, you should see 5 vertical bars of increasing heights animate. Then, after 5 seconds, it switches immediately to 4 bars of descending heights. I am looking to have that update animate.
Here is some reference information I've reviewed:
CanvasJS React Demos: many of which animate on initial draw, but I couldn't find one that animates with dynamic data loaded after the initial render.
Chart using JSON Data is an demo that has dynamic data, but doesn't animate.
Reviewing the CanvasJS forum, I found a couple links, but none that address React functional components
Vishwas from Team Canvas said:
To update dataPoints dynamically and to animate chart, you can instantiate the chart, update dataPoints via chart-options and then call chart.render as shown in this updated JSFiddle.
var chart = new CanvasJS.Chart("chartContainer", {
title: {
text: "Animation test"
},
animationEnabled: true,
data: [{
type: "column",
dataPoints: []
}]
});
chart.options.data[0].dataPoints = [{ label: "Apple", y: 658 },
{ label: "Orange", y: 200 },
{ label: "Banana", y: 900 }];
chart.render();
This sample is pure JS, but I tried to adapt the principle to my React functional component. To better comport with React best practices, I incorporated the useState hook for storing the data and the useEffect hook to handle the fetch. But, alas, I couldn't get my sandbox to animate with the dynamic data.
I think the problem is that CanvasJS expects to animate only on the first render, as stated by Sanjoy in the CanvasJS forum on 7/19/2016.
I found this SO question from Jan 2015 that suggests:
My current ugly workaround is to reinstantiate the chart every time I
update just to achieve that animation effect.
I'm hopeful that the situation has improved in the last four years, but if this hack is still the best/only way to go, I need some guidance on how to reinstantiate the chart every time using a React functional component.
To force a remount of a component pass a different key when you want to remount the component
<CanvasJSChart
key={dataPoints.toString()} // force a remount when `dataPoints` change
containerProps={containerProps}
options={options}
onRef={ref => (chart.current = ref)}
/>
Working example
I found a partial answer. Full executing code is in this code sandbox, but the critical bit is to delay the initial render of the chart until a state variable indicates that the data is available:
return (
<div className="App">
{!initialized ? (
<h1> Loading...</h1>
) : (
<CanvasJSChart containerProps={containerProps} options={options} />
)}
</div>
);
This is only a partial solution because subsequent data updates still do not animate.
Both examples works fine.
You can always animate chars with some kind of calling. I use in this case setInterval.
<script src="https://canvasjs.com/assets/script/canvasjs.min.js"></script>
<script>
var chart;
window.onload = function () {
chart = new CanvasJS.Chart("chartContainer", {
title: {
text: "Animation test"
},
animationEnabled: true,
data: [{
type: "column",
dataPoints: []
}]
});
chart.options.data[0].dataPoints = [{ label: "Apple", y: 0 },
{ label: "Orange", y: 0 },
{ label: "Banana", y: 0 }];
chart.render();
}
var max = 0;
var s = {c: 0, i: 0};
function ANIMATE() {
if (typeof chart === 'undefined') return;
chart.options.data[0].dataPoints.forEach(function(item, index, array) {
if (index == s.i) {
array[index].y += 3;
s.c++;
}
if (s.c > 12) {
s.i++;
s.c = 0;
if (s.i == 15) { s.i = 0}
}
});
if (max < 12) {
chart.options.data[0].dataPoints.push({label: "apple" + Math.random(), y: 1 + Math.random() * 10});
max++;
}
chart.render()
}
setInterval(function(){
ANIMATE()
}, 1)
</script>
<div id="chartContainer" style="height: 370px; width: 100%;"></div>

Enzyme+React expect component string - failed to parse selector

So I have this test case which I need to solve. Background is updating dev environment to newer version and after that a lot of our tests broke.
Here I have a weird case which results in:
"Failed to parse selector: Label price detail 1"
This is how the test snippet looks like, I hope I've added all that is necessary.
it('Should render with price and one addon', () => {
data.addonHeaderName = 'addonHeaderName';
data.addons.push(
{
price: {
label: 'Addon text 1',
value: 50.33,
unit: 'dollars',
vat: 'excl'
},
discount: {
label: 'Addon text 2',
value: 11.43,
unit: 'dollars',
vat: 'excl'
},
future: false,
addonIcon: 'icon',
ecoText: 'Addon eco text',
linkUrl: 'http://testaddonlink.com'
}
);
data.contract.prices.push(
{
id: 'price',
label: 'Label price detail 1',
unit: 'dollars',
value: 4.03
},
{
id: 'Label price detail 2',
label: 'Discount',
unit: 'dollars',
value: -3.00
}
);
const component = shallow(
<MyContract
data={data}
andSomeOtherStuff={otherStuff}
/>
);
expect(component).toMatchSnapshot();
expect(component.find('Label price detail 1')).toBeTruthy();
expect(component.find('Label price detail 2')).toBeTruthy();
expect(component.find('Addon text 1')).toBeTruthy();
expect(component.find('Addon text 2')).toBeTruthy();
expect(component.find('Addon eco text')).toBeTruthy();
If I comment out the first expectation, it hits the next one, and then the other one etc etc.
Earlier we ran Enzyme 2.9.1 together with enzyme-adapter-react-15 (and of course React 15) but since we've upgraded to React 16 we also need to update a few other dependencies such as this one. And then shit hit the fan.
Now we're on Enzyme 3.8.0, enzyme-adapter-react-16.3 and React 16.3.x.
I've been fiddling around with trying to get it as a string instead but no bueno. Any ideas on what I'm missing here?
Enzyme find works with css selectors so if you would like to search on the label there you should probably use something like:
component.find('[label="Label price detail 1"]')
Additionally I believe this will always be truthy no matter if it's found or not. (Not sure on that one though).
I usually use .toHaveLength(1) to check if it gets rendered!
I had this before, this looks like a typing error. Confirm the strings.

AngularJS issue with ng-click and 2 expressions inside, only one fires

I have an issue, in a ng-click I have 2 expressions, and only one fires.
If I use only one expression at a time, they both work, but together they dont.
One is a function, and one is a simple: button = !button ; which I use to trigger the button state.
All of this is inside a ng-repeat, so I'll get multiple buttons, and each has to have its own state.
What I saw is that if instead of doing: button = !button which will only work alone, but not together with the function ( so ng-click= "func(); button = !button" won't fire the second expression).
but If I declare a simple bool in the controller like this:
button: boolean;
this.button = false;
then use: ng-click= "func(); $scope.button = !$scope.button"
It will fire both expression correctly, but the issue here is that I'm using a ng-repeat, so if 10buttons get generated, when you click one, with this solution, all the 10 buttons will get triggered because they are using the same bool.
So to avoid adding a new property on my list of objects that I loop over, just for the button state, is there a simpler solution?
I don't even understand why using a declared boolean in the controller would work, and using a simple: var = !var in the view won't.
I tried using instead a dummy function, with just a console.log return and it works, so it has also probably something to do with my function, but yet again, why would it work with a declared bool and not with a direct expression in the view?
the function is a bit long and calls other functions inside it, so for the purpose of my question I don't think it's relevant posting it and making a fiddle would also be complicated as the function takes data directly from the API.
But the important thing is that the function works correctly and it's used in multiple places in the project.
Thank you
You can try like the below code which will let you do what you are looking for, also please check this plunker for your example scenario.
Template:
<div ng-repeat="btn in buttonList">
<button type="button" value="btn.value" ng-click="func();btn.button=!btn.button" ng-disabled="btn.button">{{btn.name}}</button>
</div>
Controller:
$scope.buttonList = [{
name: 'World1',
value: 1
}, {
name: 'World2',
value: 2
}, {
name: 'World3',
value: 3
}, {
name: 'World4',
value: 4
}, {
name: 'World5',
value: 5
}, {
name: 'World6',
value: 6
}, {
name: 'World7',
value: 7
}, {
name: 'World8',
value: 8
}];

Dropdown opening issue inside of ui-grid

I get a new row on dropdown Click and am using enableCellEditOnFocus and when I try to open the dropdown it is not opening and alternate dropdowns are working properly. To avoid confusion I altered the code and I am showing that bit of code that is giving me the error and here is my plunker.
This is my ui-grid object
$scope.gridOptions = {
enableCellEditOnFocus: true
};
$scope.gridOptions.columnDefs = [
{ name: 'gender', displayName: 'Gender', editableCellTemplate: 'ui-grid/dropdownEditor', width: '20%',
editDropdownValueLabel: 'gender', editDropdownOptionsArray: [
{ id: 1, gender: 'male' },
{ id: 2, gender: 'female' }
] } ];
I add new row by using this code:
$scope.addNewRow = function () {
$scope.gridOptions.data.push({
"gender": "male"});
};
//adding new row inside of uigrid
$scope.newRow = function (row, columnIndex) {
tempIndexSave = "";
tempIndexSave = _.indexOf($scope.gridOptions.data, row);
var length = $scope.gridOptions.data.length;
if (length - 1 == tempIndexSave) {
$scope.addNewRow();
}
};
The problem is due to these lines where you can see there's a hack for screen readers.
This hack may bring issues similar to yours because it depends on beginCellEdit and afterCellEdit events to be fired evenly and with a fixed pattern:
beginCellEdit
afterCellEdit
beginCellEdit
afterCellEdit
beginCellEdit
...
Adding a new row while already editing a row breaks this pattern since, for the new created row, you are missing a beginCellEdit, so the preventMouseDown function will always fire, preventing user interaction.
I put up a workaround, but I don't advise you using this if you want to keep compatibility with screen readers (see comments before the lines in the file I linked to), because the workaround might break the hack.
The workaround consists of raising a fake beginCellEdit while adding the row, as you can see in this updated plunkr.
...
if (length - 1 == tempIndexSave) {
$scope.addNewRow();
$scope.gridApi.edit.raise.beginCellEdit();
}
...

Resources