Use Ionic plugin in a Web Worker - angularjs

How can I use an ionic plugin in a Web Worker? Specifically, org.apache.cordova.contacts if that helps.
Inspired by "Is it possible to run Angular in a web worker?" I'm trying to do:
self.window = self;
self.window.Event = function() {};
self.window.innerHeight = 1;
self.history = {};
self.document = {
readyState: 'complete',
addEventListener: function() {},
querySelector: function() {},
getElementsByTagName: function() {
return [];
},
createElement: function() {
return {
pathname: '',
setAttribute: function() {}
};
},
createEvent: function() {
return {
initEvent: function() {}
};
},
documentElement: {
style: {
transition: ''
}
},
head: {
children: [],
appendChild: function(child) {
importScripts('../../' + child.src);
child.onload();
}
},
body: {
classList: {
add: function() {},
}
},
};
importScripts('../../lib.js');
importScripts('../../cordova.js');
This gets it to load, but navigator.contacts.find is undefined after running that. :(
Is there an easier way? My end goal is to ingest the phone's contacts asynchronously.
(I need to do this because navigator.contacts.find() is a blocking call and to download the whole contact list is taking around 1 minute).

Related

Error when updating ReactJS state with complex object

When I do something like:
getInitialState: function() {
return { previews: [], isLoading: true, error: "", nextCursor: "" };
},
componentDidMount: function(){
$.ajax("/my-url", {
method: "GET",
success: this.previewsReceived,
failure: this.previewsFailedToReceive
});
},
previewsReceived: function(previews){
var tmpState = { isLoading: false, previews: previews.data, nextCursor: previews.next_cursor, error: "" };
this.setState(tmpState);
},
previewsFailedToReceive: function(_){
this.setState(Object.assign({}, this.state, { error: "", isLoading: false, previews: [], nextCursor: "" }));
},
I get the following reactJS error:
Uncaught [object Object]
on line 1093 in the react.js library (in the method invariant).
If I am not passing any complex object (inside my previews data) to the state however, I do not get the error.
Any idea about what I am doing wrong?
Edit: Here is the whole component, addressing the first answer, I still get the same errors.
var Creatives = React.createClass({
getInitialState: function() {
return { previews: [], isLoading: true, error: "", nextCursor: "" };
},
componentDidMount: function(){
$.ajax("/my-url, {
method: "GET",
success: this.previewsReceived.bind(this),
failure: this.previewsFailedToReceive.bind(this)
});
},
previewsReceived: function(previews){
var tmpState = { isLoading: false, previews: previews.data, nextCursor: previews.next_cursor, error: "" };
this.setState(tmpState);
},
previewsFailedToReceive: function(_){
this.setState({ error: "", isLoading: false, previews: [], nextCursor: "" });
},
render: function() {
return <ul>
{this.state.previews.map(function(creative) {
return <li key={creative.tweet_id} style="width: 450px">
<input type="checkbox" style="float:left;margin-top: 10px" />
<CreativePreview creative={creative} /></li>;
})
}
</ul>;
}
});
I also get the following warning when I call bind:
Warning: bind(): You are binding a component method to the component.
React does this for you automatically in a high-performance way,
so you can safely remove this call. See Creatives
Edit2: I found out that removing most of the render method 'fixes' the error. So I am gonna post the definition of that component too:
var CreativePreview = React.createClass({
render: function() {
return <iframe
id={ 'iframe-tweet-id-'+ this.props.creative.tweet_id }
dangerouslySetInnerHTML={this.props.creative.preview}>
</iframe>;
}
});
I don't think dangerouslySetInnerHtml works like you want it to on <iframe> elements.
You can populate it directly by creating a ref to your <iframe> element:
var CreativePreview = React.createClass({
componentDidMount: function(){
var frame = React.findDOMNode(this.refs.myFrame);
frame.document.body.innerHTML = this.props.creative.preview;
},
render: function() {
return <iframe ref='myFrame' />;
}
});
The error is most likely in CreativePreview. Try to remove it to see if it fixes your problem.
Side note: Object.assign() calls are unnecessary with React's setState. The setState method will automatically merge with the current state.
EDIT:
It seems that React will now auto-bind this for component functions.
EDIT 2:
Now we can see CreativePreview.
There were several errors in my code:
Inline class and style in html tags were assuming actual html conventions and not jsx format.
The iframe was very hard to implement in reactJS. I found a workaround inspired from https://github.com/ryanseddon/react-frame-component but since it didn't work out of the box, I used vanilla Javascript in it:
--
var CreativeFrame = React.createClass({
render: function() {
var style = { width: '420px', border: 'none', height: '280px' };
return <iframe
style={style}
className="tweet-content"
id={ "iframe-tweet-id-" + this.props.creative.tweet_id }>
</iframe>;
},
componentDidMount: function() {
this.renderFrameContents();
},
renderFrameContents: function() {
// Proof that good old Javascript >> Any library
var iframe = document.getElementById("iframe-tweet-id-" + this.props.creative.tweet_id);
var iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
iframeDoc.body.innerHTML = this.props.creative.preview;
},
componentDidUpdate: function() {
this.renderFrameContents();
},
componentWillUnmount: function() {
var doc = ReactDOM.findDOMNode(this).contentDocument;
if (doc) {
ReactDOM.unmountComponentAtNode(doc.body);
}
}
});
If anybody knows about improvements on it, let me know.

Saving simple user input in angular JS

I have built this simple todo app, however it resets the data every time the users page is reset, how can I save the data in the checklist list upon page refresh so the user can reference it later? Can this be done within the app or do I need a server database setup?
var checkList = angular.module('checkList', []);
checkList.filter('checkedItems', function () {
return function (items, showComplete) {
var resultArr = [];
angular.forEach(items, function (item) {
if (item.done == false || showComplete == true) {
resultArr.push(item);
}
});
return resultArr;
}
});
checkList.controller('CheckListCtrl', function($scope){
$scope.check = {
user: "Jim",
items: [ {action: "item1", done: false },
{action: "item2", done: false },
{action: "item3", done: false },
{action: "item4", done: false }]
};
$scope.incompleteCount = function () {
var count = 0;
angular.forEach($scope.check.items, function (item) {
if (!item.done) { count++ }
});
return count;
}
$scope.warningLevel = function () {
return $scope.incompleteCount()
< 3 ? "label-success" : "label-warning";
}
$scope.addNewItem = function (actionText) {
$scope.check.items.push({ action: actionText, done: false });
}
});
The easiest way is:
To save data in browser's local storage: localStorage.setItem('itemName', data) and then, to retrieve it back localStorage.getItem('itemName', data)

Angular translate inside service

I am struggling with angular translate for my ionic app. The thing is that I have a service with data to share between views but I need to translate this data. Unfortunately I just see blank screen without any errors in console.
I would appreciate if someone could help if there is something wrong with that code (I use useStaticFilesLoader):
app.service('customService', function($q, $rootScope, $filter, $translate) {
$rootScope.$on('$translateChangeSuccess', function () {
var $translate = $filter('translate');
return {
items: [
{
id: '1',
title:$translate('TITLE');
}
]
],
getItems: function() {
return this.items;
},
getItem: function(itemId) {
var dfd = $q.defer();
this.items.forEach(function(item) {
if (item.id === itemId) dfd.resolve(item);
});
return dfd.promise;
}
};
});
});
Try something like this:
app.factory('customService', function($rootScope, $translate) {
var items = [],
updateItems = function() {
items.length = 0;
$translate('TITLE').then(function(title) {
items.push({
id: '1',
title: title;
});
});
};
updateItems();
$rootScope.$on('$translateChangeSuccess', updateItems);
return {
items: items,
getItem: function(itemId) {
var result;
items.forEach(function(item) {
if (item.id === itemId) {
result = item;
}
});
return result;
}
}
});

create/update user story using rally app sdk

Until now, I have been querying the data stores using Rally App SDK, however, this time I have to update a story using the js sdk. I tried looking up for examples for some sample code that demonstrates how the App SDK can be used to update/add values in Rally. I have been doing CRUD operations using Ruby Rally API but never really did it with the app sdk.
Can anyone provide some sample code or any link to where I could check it out?
Thanks
See this help document on updating and creating reocrds. Below are examples - one updates a story, the other creates a story. There is not much going on in terms of UI: please enable DevTools console to see console.log output.
Here is an example of updating a Defect Collection on a User Story:
Ext.define('CustomApp', {
extend: 'Rally.app.App',
componentCls: 'app',
launch: function() {
console.log("launch");
Rally.data.ModelFactory.getModel({
type: 'User Story',
success: this._onModelRetrieved,
scope: this
});
},
_onModelRetrieved: function(model) {
console.log("_onModelRetrieved");
this.model = model;
this._readRecord(model);
},
_readRecord: function(model) {
var id = 13888228557;
console.log("_readRecord");
this.model.load(id, {
fetch: ['Name', 'Defects'],
callback: this._onRecordRead,
scope: this
});
},
_onRecordRead: function(record, operation) {
console.log('name...', record.get('Name'));
console.log('defects...', record.get('Defects'));
if(operation.wasSuccessful()) {
//load store first by passing additional config to getCollection method
var defectStore = record.getCollection('Defects', {
autoLoad: true,
listeners: { load: function() {
//once loaded now do the add and sync
defectStore.add({'_ref':'/defect/13303315495'});
defectStore.sync({
callback: function() {
console.log('success');
}
});
}}
});
}
},
});
Here is an example of creating a user story, setting a project and scheduling for an iteration:
Ext.define('CustomApp', {
extend: 'Rally.app.TimeboxScopedApp',
componentCls: 'app',
scopeType: 'iteration',
comboboxConfig: {
fieldLabel: 'Select an Iteration:',
labelWidth: 100,
width: 300
},
addContent: function() {
this._getIteration();
},
onScopeChange: function() {
this._getIteration();
},
_getIteration: function() {
var iteration = this.getContext().getTimeboxScope().record.get('_ref');
console.log('iteration',iteration);
if (!this.down('#b2')) {
var that = this;
var cb = Ext.create('Ext.Container', {
items: [
{
xtype : 'rallybutton',
text : 'create',
id: 'b2',
handler: function() {
that._getModel(iteration);
}
}
]
});
this.add(cb);
}
},
_getModel: function(iteration){
var that = this;
Rally.data.ModelFactory.getModel({
type: 'UserStory',
context: {
workspace: '/workspace/12352608129'
},
success: function(model) { //success on model retrieved
that._model = model;
var story = Ext.create(model, {
Name: 'story 777',
Description: 'created via appsdk2'
});
story.save({
callback: function(result, operation) {
if(operation.wasSuccessful()) {
console.log("_ref",result.get('_ref'), ' ', result.get('Name'));
that._record = result;
that._readAndUpdate(iteration);
}
else{
console.log("?");
}
}
});
}
});
},
_readAndUpdate:function(iteration){
var id = this._record.get('ObjectID');
console.log('OID', id);
this._model.load(id,{
fetch: ['Name', 'FormattedID', 'ScheduleState', 'Iteration'],
callback: function(record, operation){
console.log('ScheduleState prior to update:', record.get('ScheduleState'));
console.log('Iteration prior to update:', record.get('Iteration'));
record.set('ScheduleState','In-Progress');
record.set('Iteration', iteration);
record.set('Project', '/project/12352608219')
record.save({
callback: function(record, operation) {
if(operation.wasSuccessful()) {
console.log('ScheduleState after update..', record.get('ScheduleState'));
console.log('Iteration after update..', record.get('Iteration'));
}
else{
console.log("?");
}
}
});
}
})
}
});

AngularJS - self referencing services?

I'm building an Angular app that will have a top-level Controller and a second-level controller. There will be n number of second-level controllers, but I want to put global-level functions someplace. I'm doing this in a service.
I'm starting down the path of creating a single service that return an api, really, containing lots of functions (below). The service is returning an object with two property branches that each contain a set of functions. How can I call one of these from the other?
globalModule.factory('global', function($http) {
var squares = MyApp.squares; // this is the *only* link from Global namespace to this app
return {
squareMgr: {
getSquaresEarned: function() {
return squares.earned;
},
getSquaresPlaced: function() {
return squares.placed;
},
setThisSquareEarned: function(value) {
squares.earned.push(value);
},
setThisSquarePlaced: function(value) {
squares.placed.push(value);
}
},
missionMgr: {
missionInfo: {},
setMissionInfo: function(missionInfo) {
this.missionInfo = missionInfo
},
complete: function(missionData) {
log('complete called on video at ' + new Date());
missionData.complete = true;
log(angular.toJson(missionData));
$http({
url: '/show/completeMission',
method: "POST",
data: missionData
})
.then(function(response) {
if (response.data.success === true) {
log('completeMission success');
// increment squares earned counter
this.squareMgr.setThisSquareEarned(missionData.id);
// above is an attempt to run a function contained in this
// same service in a different parent property branch.
// how *should* I do this?
}
});
}
}
}
});
How about something like this:
globalModule.factory('global', function($http) {
var glob = {
squareMgr: {
// ...
},
missionMgr: {
foo: function() {
glob.squareMgr.xyz();
}
}
};
return glob;
});

Resources