I have not come across another js plugin for a lucky spinning wheel better than this one yet. I'm having an issue with the getIndicatedSegment property when calling the alert prize(); function in an Ionic 3/Angular 2 application. I've followed this issue how to use winwheel.js callback in angular2 and have gotten it to work with the app and spinning quite well.
When the alert prize function is called, I get this error:
TypeError: Cannot read property 'getIndicatedSegment' of undefined
at alertPrize (http://localhost:8100/?ionicplatform=ios:51:41)
at eval (eval at winwheelStopAnimation
I've followed the advice in that answer and added the prize function in my index.html file in order to get access to the Prize callback that is in my page.ts file and show the alert on the basic example to alert the prize. However, when I am trying to access the getIndicatedSegment variable, I get this issue.
Here is the code in my LuckySpinPage.ts file:
export class LuckySpinPage {
constructor(public navCtrl: NavController) { }
wheel;
wheelSpinning = false;
ngAfterViewInit() {
this.initWheel();
}
initWheel() {
this.wheel = new Winwheel({
'numSegments': 10, // Specify number of segments.
'outerRadius': 150, // Set radius to so wheel fits the background.
'innerRadius': 30, // Set inner radius to make wheel hollow.
'pointerAngle': 0,
'pointerGuide': false, // Turn pointer guide on.
'drawMode' : 'segmentImage',
'segments': [
{'image' : '../../assets/images/segment-winner.png'},
{'image' : '../../assets/images/segment-1.png'},
{'image' : '../../assets/images/segment-2.png'},
{'image' : '../../assets/images/segment-3.png'},
{'image' : '../../assets/images/segment-5.png'},
{'image' : '../../assets/images/segment-6.png'},
{'image' : '../../assets/images/segment-7.png'},
{'image' : '../../assets/images/segment-8.png'},
{'image' : '../../assets/images/segment-9.png'},
{'image' : '../../assets/images/segment-10.png'}
],
'animation': // Define spin to stop animation.
{
'type': 'spinToStop',
'duration': 5,
'spins': 10,
'callbackFinished': 'alertPrize()'
}
});
}
// -------------------------------------------------------
// Click handler for spin button.
// -------------------------------------------------------
startSpin() {
// Ensure that spinning can't be clicked again while already running.
if (this.wheelSpinning === false) {
this.wheel.startAnimation();
this.wheelSpinning = true;
}
}
}
The code in the index.html file:
<script>
// This function called after the spin animation has stopped.
function alertPrize(){
// Call getIndicatedSegment() function to return pointer to the segment
pointed to on wheel.
var winningSegment = this.wheel.getIndicatedSegment();
// Basic alert of the segment text which is the prize name.
alert("You have won " + winningSegment.text + "!");
}
</script>
My aim is to get the prize on a specific segment e.g alert you've won, when it lands on segment 4, or alert not prize won when landing on any other segment.
Related
I'm using ngMap in an angularjs app. I'm running into an error when I try to set the zoom on a map element. Here's the error message from the Chrome console:
TypeError: Cannot read property 'apply' of undefined
at Wk.eventFunc (ng-map.js:205)
at Object.T.trigger (main.js:18)
at kf (main.js:22)
at Wk.N.set (main.js:21)
at Wk.setZoom (main.js:29)
at ng-map.js:1568
at angular.js:6837
at forEach (angular.js:323)
at Object.$get.Attributes.$set (angular.js:6835)
at interpolateFnWatchAction (angular.js:8157)
This is being triggered when the zoom attribute of my map element:
<map center="{{initCenter.lat}}, {{initCenter.lng}}" zoom="{{zoom}}" on-dragend="dragend()" on-zoom_changed="zoomchanged()">
is being bound to my angular controller:
app.controller("mapCtrl", function ($scope, $location, dataContext) {
$scope.markers = [];
$scope.initCenter = dataContext.center();
$scope.zoom = dataContext.zoom();
dataContext is a service that exposes various state variables in the app. I've also tried setting $scope.zoom through a function, with the same resulting error.
The error takes place on line 1568 of the ng-map.js file:
var observeAndSet = function(attrs, attrName, object) {
attrs.$observe(attrName, function(val) {
if (val) {
void 0;
var setMethod = parser.camelCase('set-'+attrName);
var optionValue = parser.toOptionValue(val, {key: attrName});
void 0;
if (object[setMethod]) { //if set method does exist
/* if an location is being observed */
if (attrName.match(/center|position/) &&
typeof optionValue == 'string') {
_this.getGeoLocation(optionValue).then(function(latlng) {
object[setMethod](latlng);
});
} else {
// this is the line that causes the problem
object[setMethod](optionValue);
}
}
}
});
};
In trying to trace through what's happening I followed the execution for setting center and for setting zoom (setting center doesn't cause a problem). Setting the center executes line 1568 and continues on its merry way.
Setting zoom (via the setZoom function) causes code at line 196 in ng-map.js to execute:
var eventFunc = function(attrValue) {
var matches = attrValue.match(/([^\(]+)\(([^\)]*)\)/);
var funcName = matches[1];
var argsStr = matches[2].replace(/event[ ,]*/,''); //remove string 'event'
var args = scope.$eval("["+argsStr+"]");
return function(event) {
function index(obj,i) {return obj[i];}
var f = funcName.split('.').reduce(index, scope);
// this next line causes an exception in google map main.js
f.apply(this, [event].concat(args));
scope.$apply();
}
}
Line 205 leads to the exception that results in the error inside google map's main.js file.
Any idea what's causing this? And how to solve it :)?
Possible Solution
Playing around with this a bit more I noticed that it isn't setting the zoom level per se which causes the problem. It's actually the result of the zoomchanged event firing >>after<< the zoom is changed.
The first time zoom is set on the map, line 204:
var f = funcName.split('.').reduce(index, scope);
evaluates to null. I'm not sure why that is, because I don't understand what that line is doing.
However, the future changes to zoom have that same line 204 resolving to a non-null value for f.
So, as a workaround, I bracketed lines 205 and 206 like this:
if (f != null) {
f.apply(this, [event].concat(args));
scope.$apply();
}
and the error went away.
I think this has the same problem with this issue, https://github.com/allenhwkim/angularjs-google-maps/issues/181
and it's resolved with the release of 1.7.7.
I used $timeout, instead of $apply.
Basic example of what i want to build :
I want a class "Fire" with attributes : "power" and "position".
I want a "Manager" who can have access to a list of Fire. I also need to share the "Fire" model to others class so i think i need to build a factory.
First shot, i did this :
// FACTORY
simuApp.factory('FireFactory', function() {
return {
list_fire: [],
createFire: function(p_power) {
return {
id : null,
power : p_power,
position : {
x: null,
y: null
}
}
}
}
});
But i feel there's something wrong.
I cannot hold the list of fires and have a method to create a fire.
I'm totally lost, can you help me to understand a good implementation ?
In a angular factory I have a method to create a new item, which has a connection to a user and a price to add to that users "items" array (like a shopping cart). So I have to see if the user is present in my the local users array if not then on the server and if not then create the user.
Code looks like this:
var saveItem = function (item) {
var user = filterUserById(item.ownerId);
if (user) {
user.createItem(item);
} else {
repository.getUserById(item.ownerId).then(
function (serverUser) {
var userViewModel = repository.getUserViewModel(serverUser);
userViewModel.createItem(item);
users.push(userViewModel);
}
, function () {
user = {
id: item.ownerId,
items: [
createItemDto(item)
]
};
repository.createUser({ id: user.id }, user);
users.push(repository.getUserViewModel(user));
});
}
};
No matter which of the "cases" occurs (user was found localy, on the server or was created and added) I get an error:
Error: [$rootScope:inprog] $apply already in progress
http://errors.angularjs.org/1.3.0-beta.18/$rootScope/inprog?p0=%24apply
I recon this may have to do with the fact that I'm using resources in my repository, but I don't think resource should (since it's a part of angular..). Here's the user.createItem method, code:
user.createItem = function (item) {
var resource = userResource
, itemDto = createItemDto(item)
, command = [{
Type: 'add',
Name: 'items',
Value: itemDto
}];
resource.createItem({ id: item.ownerId }, command);
this.items.push(itemDto);
};
Y U NO WERK!? PLS HLP! :'(
P.S. I don't have any explicit calls to apply, compile or digest anywhere in my code.
Found the problem! I had put a small code line to set focus on the correct input after the item was added and form was emptied. This consisted of a
$('selector').focus();
This was colliding with digest cycle... Solution:
$timeout($('selector').focus());
Try wrapping your call to user.createItem(item) in a $timeout function:
$timeout(function() {
user.createItem(item);
}, 0);
It's possible you could be triggering some other call to $scope.$apply() some other way.
Alternatively, try using $scope.$evalAsync(function())
Here's some good info: inprog
I wasn't sure how to describe my question in the question title. But here is my problem:
(a) When I double click on a row in an Ext.grid.Panel, I open a modal window with it's relavant details to update the record.
(b) After I make the needed modifications and close the modal window, I want to return to the Grid with the Grid filtered on a certain code i.e selectedSalesOrderNum.
jobSlotsGrid.on('celldblclick', function(tableview, td, cellIndex, record, tr, rowIndex, e, eOpts){
modalStatus = loadWindow();
jobSlotStore.filterBy(function(rec) {
alert('Filtering data');
return rec.get('salesOrderNum') === selectedSalesOrderNum;
});
});
(c) Below is the function, which creates the model window. It also has the call to method submitCreateJobSlotHandler() which basically saves the changes and reloads the original Grid with all the data. ( Hence the necessity to filter it back with a certain code i.e selectedSalesOrderNum ).
function loadWindow()
{
getAllTabsForEditJobSlot();
var createJobSlotWin = new Ext.Window({
id:'salesOrder-win-jobSlot',
applyTo : 'hello-win',
modal : true,
layout : 'fit',
width : 900,
height : 500,
closeAction :'destroy',
plain : true,
model : true,
stateful : false,
title :'Create Job Slot',
items : [editJobSlotInformationPanel],
buttons : [{
text : 'Save',
handler : function(){
submitCreateJobSlotHandler();
//createJobSlotWin.destroy();
}
},{
text : 'Close',
handler : function(){
createJobSlotWin.destroy();
}
}]
});
createJobSlotWin.show();
}
The Issue:
In the first block of code, as soon as the loadWindow method is called, both a modal window is popped up along with the filterBy code getting executed in parallel and showing up the alerts ( 'Filtering data' ). I then enter the data in the modal and save. So, basically, the filtering is not done after the Save/Close on Modal. The code ( if/else ) is immediately reached after loading the modal window. It is as if, the modal window opens and goes to the next line of code while waiting for the user to perform some action on the modal window later.
Hope I am clear on my question. Could anyone please advice how do I handle this?
EDIT:
The more I think about it now, I guess the loadWindow() method just creates the Modal Window as we just have a new Ext.Window() call and doesn't bother about other user actions inside the modal and returns the control. And hence, executes the subsequent filterBy event immediately. In that case, I want to filter the store after I am reloading the store upon the Save in Modal Window. The save on Modal window has this handler code:
function submitCreateJobSlotHandler () {
alert('Into Submit');
var formPanel = Ext.getCmp('salesOrderJobSlotForm');
formPanel.getForm().submit({
url : 'someUrl',
method : 'POST',
success : function() {
alert('Success');
jobSlotStore.load({
scope : this,
url : 'salesOrderJobSlot/listJSON'
});
jobSlotStore.filterBy(function(rec) {
alert(rec.get('salesOrderNum')+"--"+selectedSalesOrderNum)
return rec.get('salesOrderNum') === selectedSalesOrderNum;
});
},
failure : function() {
alert('PSO save failed!');
}
});
}
But the issue here is, the jobSlotStore.load() though gets called, it holds until the filterBy gets executed. Because, I see the alerts coming up one by one and then after all the alerts are done, the store loads. So, the filterBy gets overriden by the 'late' store load.
Any suggestions to deal with the issue in any of the ways?
The store load is asynchronous, you need to wait til it completes before you can filter the data set on the client:
store.on('load', function() {
store.filter();
}, null, {single: true});
store.load();
I've created a new plug in as I could not find one that actually "works", hoping that if I do it from scratch it might fire.
The plug-in simply wraps selected text with a mailto: link.
I've added the plug-in to the includes file, as per the following response on a previous question: http://bit.ly/vGyQlE however, it's not working.
I've gone into the localization directory, identified the Composite.Web.VisualEditor.en-us.xml as the file that handles the localization, added my entry under :
<string key="ToolBar.ToolTipMailTo" value="Mail To" />
But when I hover of the "blank" block where the menu item should appear, it returns (?). This is the first part where I picked up on something wierd. When you actually click on where the item should appear, nothing happens. So, I can't assume that the click event has got to do with an image, I re-wrote the command to return an alert, when clicked:
tinymce.create('tinymce.plugins.MailTo', {
init : function(ed, url) {
ed.addButton('mailto', {
title : 'mailto.mailto_desc',
cmd : 'mceMailTo',
image : url + '/images/mailto.gif'
});
ed.addCommand('mceMailTo', function() {
var selectedText = ed.selection.getContent({format : 'text'});
var MailToLink = "alert(" + selectedText + ");";
ed.execCommand('mceInsertContent', false, MailToLink);
});
I've added the "mailTo" element to visualeditor.js:
plugins : "...,paste,lists,mailto",
And ensured that the "mailto" plug-in is situated under the plug-ins directory for tiny_mce. I've gone as far as to clear my cache several times, but nothing? Can it be this difficult to add new plug-ins to tiny-mce in Composite?
1) Composite C1 does not support internal tiny_mce buttons
Do you add button to editor?
In file Composite\content\misc\editors\visualeditor\includes\toolbarsimple.inc add
<ui:toolbargroup>
<ui:toolbarbutton cmd="mceMailTo" tooltip="Mail to" image="${icon:paste}" isdisabled="false" />
</ui:toolbargroup>
2) Do you write valid plugin code?
(function () {
tinymce.create('tinymce.plugins.MailTo', {
init: function (ed, url) {
ed.addCommand('mceMailTo', function () {
var selectedText = ed.selection.getContent({ format: 'text' });
var MailToLink = "alert(" + selectedText + ");";
ed.execCommand('mceInsertContent', false, MailToLink);
});
}
});
tinymce.PluginManager.add('mailto', tinymce.plugins.MailTo); })();