load data from chrome.storage into vue.js data - google-chrome

I'm building a chrome app and I use Vue.js for the options page.
So I want to load settings from the chrome storage and put it into the vue data.
My problem is, that i can not access the vue compontens from inside the chrome storage callback. Every time i call it inside the callback, all vue elements are undefined.
Is there a way, to let the chrome storage cb function return a value, or give it an extra callback.
Here is my code
name: 'app',
data: function () {
return {
data []
}
},
methods: {
init: function() {
chrome.storage.sync.get('series', function (storageData) {
this.data = storageData //this is not possible, because this.data is undefined
})
});
}
},
created: function () {
this.init();
}
}

If using ES6 and transpiling (preferred approach). Note: arrow functions don't create a new context.
init: function() {
chrome.storage.sync.get('series', storageData => {
this.data = storageData
});
}
ES5 workaround:
init: function() {
var self = this;
chrome.storage.sync.get('series', function (storageData) {
self.data = storageData
});
}

Related

How to Debounce with Observer Polymer

I am trying to run getResponse once when a web components finishes loading. However, when I try to run this, the debounce function just acts as an async delay and runs 4 times after 5000 ms.
static get properties() {
return {
procedure: {
type: String,
observer: 'debounce'
}
}
}
debounce() {
this._debouncer = Polymer.Debouncer.debounce(this._debouncer, Polymer.Async.timeOut.after(5000), () => {
this.getResponse();
});
}
getResponse() {
console.log('get resp');
}
What is necessary to get getResponse to run once upon the loading of the element?
Are you sure you want to use a debouncer for that? you could just use the connectedCallBack to get a one Time Event
class DemoElement extends HTMLElement {
constructor() {
super();
this.callStack = 'constructor->';
}
connectedCallback() {
this.callStack += 'connectedCallback';
console.log('rendered');
fetch(this.fakeAjax()).then((response) => {
// can't do real ajax request here so we fake it... normally you would do
// something like this.innerHTML = response.text();
// not that "rendered" get console logged before "fetch done"
this.innerHTML = `
<p>${this.callStack}</p>
<p>${response.statusText}</p>
`;
console.log('fetch done');
}).catch(function(err) {
console.log(err); // Error :(
});
}
fakeAjax() {
return window.URL.createObjectURL(new Blob(['empty']));
};
}
customElements.define('demo-element', DemoElement);
<demo-element></demo-element>
If you really need to use an observer you could also set a flag this.isLoaded in your connectedCallback() and check for that in your observer code.

Angular factory does not return array of objects but a single object

I am new to angular and I am trying to load a CSV list inside a factory and then convert it to json. I am using Papaparse (CSV to json library) inside the factory. When I console log the factory I get the array of objects which is exactly what I want but when I pass it inside my controller I get a single object which holds all the data.
This is my factory
(function() {
var app = angular.module('test');
app.factory('testFactory', ['$http', function($http) {
var url = 'my-list.csv';
var getContact = function() {
return $http.get(url).success(function(data) {
Papa.parse(data, {
header: true,
complete: function(results) {
console.log(results.data);
return results.data;
}
});
});
};
return {
getContact: getContact
};
}]);
}());
And this is my controller
(function() {
var app = angular.module('test');
app.controller('testCtrl', ['$scope', 'testFactory', function($scope, testFactory) {
testFactory.getContact().then(function(data) {
$scope.contacts = data;
console.log(data);
});
}]);
}());
I want be able to do something like this inside my view
{{ contact.firstname }}
The issue is the order of resolution. Inspecting the console statements shows that you're assigning $scope.contacts to the resolution of the $http.get promise, and not the actual parsing.
Instead of returning the $http.get promise, return a deferred promise and resolve at the end of parsing:
var parsePromise = $q.defer();
$http.get(url).success(function(data) {
Papa.parse(data, {
header: true,
complete: function(results) {
console.log(results.data);
parsePromise.resolve(results.data);
}
});
});
return parsePromise.promise;
See working demo here.
Update: As per the comments, you could use .then to chain promises instead of creating a new deferred. The plunkr has both, you can use the changelog to toggle methods.

Angular: Directive watch model defined in own controller

I try to update my chart when data is pushed to a websocket. I want to do this by defining my own directive in angular, but the binding of data does not work. The Code:
angular.directive("myChart", ['service', function (service) {
function ChartController ($scope) {
var ws = new WebSocket("url/to/websocket/");
var data = service.initData(); // initialize data table
ws.onmessage = function (event) { // listen and update data
data = service.updateData(event.data);
$scope.recentData = data;
}
$scope.recentData = data;
}
function link(scope, element, attr) {
function drawChart (data) {}
scope.$watch('data', function (newD, old) {
drawChart(newD);
}, true);
}
return {link: link, controller: ['$scope', ChartController], restrict: 'EA'}
}
Thats a simplistic example, of what i want to do. The service and data changes work well, i can log the current values. However drawChart() gets called only on startup and not on every mutation.
The Controller has to be part of the directive and not wrapped around
You need to notify angular of the changes by using a method that calls apply() after the change occurs, which is preferably done by using $timeout.
angular.directive("myChart", ['service', '$timeout', function (service, $timeout) {
function ChartController ($scope) {
var ws = new WebSocket("url/to/websocket/");
var data = service.initData(); // initialize data table
ws.onmessage = function (event) { // listen and update data
data = service.updateData(event.data);
$scope.recentData = data;
}
$scope.recentData = data;
}
function link(scope, element, attr) {
function drawChart (data) {}
scope.$watch('data', function (newD, old) {
$timeout(function(){
drawChart(newD);
});
}, true);
}
return {link: link, controller: ['$scope', ChartController], restrict: 'EA'}
}

view not gathering data from service through controller

Having trouble loading an external json file and having it's contents display on my view. I've included my view, controller and services code. What do I need to change?
view.html
<div ng-controller='BaseCtrl'>
<table class="table table-hover">
<tbody>
<tr class="tr-sep" ng-repeat="example in examples" ng-click="showUser(example)">
<td>{{example.name}}</td>
<td>{{example.type}}</td>
<td>{{example.size}}</td>
</tr>
</tbody>
</table>
</div>
controller.js
'use strict';
angular.module('projyApp')
.controller('BaseCtrl', function ($scope, data) {
$scope.examples = data.getAllExamples();
$scope.showUser = function(example) {
window.location = '#/user/' +example.size;
};
});
service.js
'use strict';
angular.module('projyApp')
.service('data', function data() {
var examples;
var getAllExamples = function () {
$http.get("../../TestData/Examples.json").success($scope.examples = data.examples);
};
});
Your service code isn't correct. I see the following problems:
You're creating a local variable getAllExamples that's not accessible from outside the service;
You're using the $http service, but that dependency isn't expressed in the service constructor;
You're trying to update the scope from the service, but it's inaccessible from there. Plus, the $scope variable is not even defined inside the service code.
Here's how your service could look like:
.service('data', function($http) {
this.getAllExamples = function(callback) {
$http.get("../../TestData/Examples.json")
.success(function(data) {
if (callback) callback(data.examples);
});
};
});
And your controller code would be like this:
.controller('BaseCtrl', function ($scope, data) {
data.getAllExamples(function(examples) {
$scope.examples = examples;
});
$scope.showUser = function(example) {
window.location = '#/user/' +example.size;
};
});
You could ditch the callback in the getAllExamples function and work directly with the $http.getreturned promise, but that's a bit more complicated.
Update Added a Plunker script to illustrate the code above.
Main module definition should look like:
angular.module("projyApp",[/*dependencies go here*/]);
Service should look like
//this use of module function retrieves the module
//Note from comments in angular doc: This documentation should warn that "angular.module('myModule', [])" always creates a new module, but "angular.module('myModule')" always retrieves an existing reference.)
angular.module('projyApp')
.service('dataService', [/*dependencies,*/function() {
var service = {
examples:[],
getAllExamples = function () {
$http.get("../../TestData/Examples.json").success(function(returnedData){examples = returnedData});
}
}
return service;
});
Controller should look like:
angular.module('projyApp')
.controller('BaseCtrl', function ($scope, dataService) {
$scope.examples = [];
$scope.showUser = function(example) {
window.location = '#/user/' +example.size;
};
$scope.$watch(function(){return dataService.examples}, function(newVal,oldVal) {$scope.examples = newVal});
});
Also you can add
debugger;
on an line to trigger Chrome to break (like a breakpoint but without having to dig through the scripts at run-time) so long as the Debugging Panel is open (F12)
You should use a callback instead of assigning in to a scope in you data service. By doing that, you can use this function in multiple controllers an assign values to appropriate scopes.
Data Service
var getAllExamples = function (callback) {
$http.get("../../TestData/Examples.json").success(function(data) {
if (typeof callback === "function") callback(data);
});
};
Controller
data.getAllExemples(function(data) {
$scope.examples = data;
});
EDIT
Another what is to create a promise object.
Data Service
var getAllExamples = function () {
return $http.get("../../TestData/Examples.json");
};
Controller
var promise = data.getAllExemples();
promise.then(function(data) {
$scope.examples = data;
});
EDIT 2
In your service, you need to return your functions
angular.module('projyApp')
.service('data', function data() {
var examples;
return {
getAllExamples: function () {
$http.get("../../TestData/Examples.json").success(...);
}
};
});

YUI3, Modules, Namespaces, calling functions

I would like to port the javascript code from my page to YUI3. After reading many posts (questions and answers) here and lots of information in the YUI3 page and in tutorials I have come to the conclusion that the best way to do it is by splitting the code in modules, because it allows me to load scripts dinamically only when needed.
I would like to organize the code in different submodules which should be loaded and managed (if needed) by a core module.
I think I have understood how to dinamically load them, but the problem I have now is that I am not always able to call the public methods both within a module and form one module to another. Sometimes it works, but sometimes I get the message xxx is not a function.
Probably the question is I don't understand how to set a global namespace (for example MyApp) and "play" within that namespace.
I would like to be able to call methods the following way: MyApp.Tabs.detectTabs()... both from the methods of the main module (MyApp.Core) and from the same submodule (MyApp.Tabs).
Here is the structure of my code:
Inline javascript:
var MyAppConfig = {
"tabpanels":{"ids":["navigation"]},
"events": [{"ids": ["main_login", "dictionary_login"],
"type": "click",
"callback": "MyApp.Core.updateContent",
"params":{
}
}]
};
YUI_config = {
filter: 'debug',
groups: {
'myapp': {
modules: {
'project-myapp-core': {
fullpath: 'http://www.myapp.com/scripts/Core.js',
requires: ['node-base']
},
'project-myapp-tabs': {
fullpath: 'http://www.myapp.com/scripts/Tabs.js',
requires: ['base', 'project-myapp-core', 'history', 'tabview', 'tabview-base']
}
}
}
}
};
YUI(YUI_config).use('node', 'base', 'project-myapp-core', function(Y) {
var MyApp = {};
MyApp.Core = new Y.MyApp.Core();
Y.on('domready', MyApp.Core.begin, Y, null, application);
});
Module: Core
File: http://www.myapp.com/scripts/Core.js
YUI.add('project-myapp-core', function(Y) {
function Core(config) {
Core.superclass.constructor.apply(this, arguments);
}
Core.NAME = 'myapp-core';
Core.ATTRS = {};
var MyApp;
MyApp = {};
Y.extend(Core, Y.Base, {
initializer: function (cfg) {
},
begin: function(e, MyAppConfig) {
MyApp.Core = instance = this;
if (MyAppConfig.tabpanels) {
YUI().use('node', 'project-myapp-tabs', function(Y) {
MyApp.Tabs = new Y.MyApp.Tabs();
});
}
if (MyAppConfig.events) {
MyApp.Core.prepareEvents(MyAppConfig.events);
// I get "MyApp.Core.prepareEvents is not a function"
}
},
prepareEvents: function(e) {
},
updateContent: function() {
}
});
Y.namespace('MyApp');
Y.MyApp.Core = Core;
}, '0.0.1', { requires: ['node-base'] });
Submodule: Tabs
File: http://www.myapp.com/scripts/Tabs.js
YUI.add('project-myapp-tabs', function(Y) {
function Tabs(config) {
Tabs.superclass.constructor.apply(this, arguments);
}
Tabs.NAME = 'myapp-tabs';
Tabs.ATTRS = {};
var tabView = [];
Y.extend(Tabs, Y.Base, {
initializer: function (cfg) {
},
begin: function (tabpanels) {
},
methodA: function () {
}
});
Y.namespace('MyApp');
Y.MyApp.Tabs = Tabs;
}, '0.0.1', { requires: ['base', 'project-myapp-core', 'history', 'tabview', 'tabview-base'] });
Where should I define the global variables, the namespace...? How should I call the functions?
Thanks in advance!
-- Oriol --
Since nothing depends on project-myapps-tabs, YUI doesn't include it. Try this in your inline JS:
YUI(YUI_config).use('node', 'base', 'project-myapp-tabs', function(Y) {