getting an error using breeze - The 'structuralTypeName' parameter must be a 'string' - angularjs

I am going through John Papa's SPA course on pluralsight and I am running into error that say The 'structuralTypeName' parameter must be a 'string' while using breeze. Here is the actual error that is being thrown
The code that is generating this error is metadataStore.getEntityType:
function extendMetadata() { names
var metadataStore = manager.metadataStore;
var types = metadataStore.getEntityType();
types.forEach(function(type) {
if (type instanceof breeze.EntityType) {
Set(type.shortName, type)
}
});
function set(resourceName, entityName) {
metadataStore.setEntityTypeForResourceName(resourceName, entityNames);
}
it is called by my prime function.
function prime() {
if (primePromise) return primePromise //if primePromise was loaded before, just return it
primePromise = $q.all([getLookups()])
.then(extendMetadata)
.then(success);
return primePromise;
function success() {
setLookups();
log('Primed the data');
}
I'm unsure what the problem is with the breeze call. Any insight into how to fix this? Thanks for your help community.
Nick
Here is the lookups query info:
function setLookups() {
var entityNames = {
personnel: 'Personnel',
cto: 'Cto',
kkeys: 'Kkey',
promotion: 'Promotion',
loa: 'Loa'
};
service.lookupCachedData = {
ctos: _getAllLocal(entityNames.cto, 'ctodate' )
kkeys: _getAllLocal(entityNames.kkeys, 'keystamp'),
promotions: _getAllLocal(entityNames.promotion, 'pdate'),
loas: _getAllLocal(entityNames.loa, 'lstrdte')
}
}
function _getAllLocal(resource, ordering) {
return EntityQuery.from(resource)
.orderBy(ordering)
.using(manager)
.executeLocally();
}
function getLookups() {
return EntityQuery.from('Lookups')
using(manager).execute()
.then(querySucceeded, _queryFailed)
function querySucceeded(data) {
log('Retrieved [Lookups] from remote data source', data, true);
return true;
}
}
function _queryFailed(error) {
var msg = config.appErrorPrefix + 'Error retrieving data from entityquery' + error.message;
logError(msg, error);
throw error;
}

You have to pass in a string to getEntityType. Sorry I missed that the first time through.
metadataStore.getEntityType('cto');
Also you are going to blow up when you are trying to call Set() function but the functions name is set() and also set is probably a keyword you aren't trying to override.

Related

Cannot read property 'emit' of undefined when trying to emit a document

I am trying to create a design for tags of entities in PouchDB with ReactJS. I managed to save my design using the put function, but when I query my design, the response is just an empty array and I am getting following error in console:
TypeError: Cannot read property 'emit' of undefined
I think the problem is in my function that I later use as a map parameter to my design variable:
function emitTagsMap(doc)
{
if (doc !== undefined)
{
if (Array.isArray(doc.tags))
{
doc.tags.forEach(x =>
{
/* Here is probably the problem - this.db is undefined */
this.db.emit(x, null);
});
}
}
};
this.db is declared in constructor:
constructor(service, name)
{
if (!service || !name) throw new Error("PouchDatabase initialized incorrectly");
this.name = name;
this.db = new PouchDB(name);
this.service = service;
this.tagsView();
}
Please bare in mind that I am completely new to PouchDB.
Any ideas how can I initialize the emit function?
Thank you in advance.
I assume, that your function is a part of a JavaScript class (otherwise you have to explain the idea with this). In ES6, you have to bind this to your regular functions. You have two options:
First - bind it via constructor:
constructor() {
this.emitTagsMap = this.emitTagsMap.bind(this);
}
Second - declare the function as an arrow one. This way, react will bind it for you:
emitTagsMap = (doc) =>
{
if (doc !== undefined)
{
if (Array.isArray(doc.tags))
{
doc.tags.forEach(x =>
{
/* Here is probably the problem - this.db is undefined */
this.db.emit(x, null);
});
}
}
};
You don't need to call emit over the database object.
Try this:
function emitTagsMap(doc)
{
if (doc !== undefined)
{
if (Array.isArray(doc.tags))
{
doc.tags.forEach(x =>
{
emit(x, null);
});
}
}
};
According to the PouchDB docs a design document is formed like this:
// first create a new design doc and pass your map function as string into it
var ddoc = {
_id: "_design/my_index",
views: {
by_name: {
map: "function (doc) { if (doc !== undefined) { if (Array.isArray(doc.tags)) { doc.tags.forEach(x => { emit(x, null); }); } } }"
}
}
};
// save it
db.put(ddoc).then(function () {
// success!
}).catch(function (err) {
// some error (maybe a 409, because it already exists?)
});
//Then you actually query it, by using the name you gave the design document when you saved it:
db.query('my_index/by_name').then(function (res) {
// got the query results
}).catch(function (err) {
// some error
});
https://pouchdb.com/guides/queries.html

Angular 7/Typescript : Create queue/array of methods

I have a requirements that some functions should be called after some method completes execution.
Below is my code of processing the queue.
processQueue() {
while (this.queue.length) {
var item = this.queue.shift();
item.resolve(item.func(item.types));
}
}
This is one of the sample function to push method in queue
getAllValues() {
let promise1 = new Promise((resolve, reject) => {
if (this.isReady) {
resolve(this._getAllValues());
} else {
this.queue.push({
resolve: resolve,
func: this._getAllValues
});
}
});
return promise1;
}
And this is one of the function which will be called on processing the queue
_getAllValues() {
var results = {}, values = this.enumInstance.enumsCache.values;
for (var type in values) {
if (values.hasOwnProperty(type)) {
results[type] = values[type][this.enumInstance.lang];
}
}
return results;
}
The issue i am facing is when i call _getAllValues() directly then i am able to access this.enumInstance.
But when same method is being accessed through processQueue() i am unable to access this.enumInstance. It gives me undefined. I think this is not referred to main class in this case.
So can anyone help me here. How can i resolve this?

AngularJS: promise in a loop

I am unable to do the promise looping.
I make a service call to get list of providers, then for each provider, I make another service call to get a customer.
A provider has 1 or more customers. So eventual list of customer is to be decorated and displayed.
In other format I am trying to achieve:
*serviceA.getProvider(){
foreach(providers){
foreach(provider.customerID){
serviceB.getCustomer(customerId)
}
}
}
.then(
foreach(Customer){
updateTheCustomer;
addUpdatedCustomerToAList
}
displayUpdatedCustomreList();
)*
I have written following code, that isn't working
doTheJob(model: Object) {
let A = [];
let B = [];
let fetchP = function(obj) {
obj.Service1.fetchAllP().then(function (response) {
let P = cloneDeep(response.data);
_.forEach(P, function(prov) {
_.forEach(prov.CIds, function(Id) {
A.push(Id);
});
});
_.forEach(A, function(CId) {
return obj.Service2.getById(CId);//what works is if this statement was: return obj.Service2.getById(A[0]);
//So, clearly, returning promise inside loop isn't working
});
})
.then(function(response) {
B.push(response.data); //This response is undefined
angular.forEach(B, function (value) {
obj.updateAdr(value)
});
obj.dispay(B);
});
};
fetchP(this);
}
forEach don't stop when you use return inside of it, try to use a plain loop instead, why you don't just loop with for ?
_.forEach(A, function(CId) {
return obj.Service2.getById(CId);
}
as stated by #Ze Rubeus if you return inside a callback within a for loop that value will be lost, since it's not returned to the caller.
probably you wanted something like this
return Promise.all(A.map(function(CId){
//collect each promise inside an array that will then be resolved
return obj.Service2.getById(CId);
})

AngularJS access JSON Object returned from $http.get

I try to access to json object generated by google api.
function getAvengers() {
return $http.get('https://maps.googleapis.com/maps/api/geocode/json?address=1600+Amphitheatre+Parkway,+Mountain+View,+CA')
.then(getAvengersComplete)
.catch(getAvengersFailed);
function getAvengersComplete(response) {
return response.data;
}
function getAvengersFailed(error) {
console.log('XHR Failed for getAvengers.' + error.data);
}
}
TestCtrl.dataTest = dataservice.getAvengers();
console.log(TestCtrl.dataTest.status);
Log generate undefined.
Could you help me?
Thanks
As getAvengers returns with a promise, you cannot use it's result as an immediate value, but you can subscribe to it's resolution. See a promise tutorial for more details.
function getAvengers() {
return $http.get('https://maps.googleapis.com/maps/api/geocode/json?address=1600+Amphitheatre+Parkway,+Mountain+View,+CA')
.then(getAvengersComplete)
.catch(getAvengersFailed);
function getAvengersComplete(response) {
return response.data;
}
function getAvengersFailed(error) {
console.log('XHR Failed for getAvengers.' + error.data);
}
}
TestCtrl.dataTest = null;
dataservice.getAvengers().then(function(data) {
TestCtrl.dataTest = data;
console.log(TestCtrl.dataTest.status);
});

Breeze 1-m-1 in HotTowel Angular with local storage

I've had a requirement recently to implement a UI for managing a many-many relationship. Ward Bell kindly provided this plunker showing how to implement using 1-m-1 with Angular and Breeze.
My app's design is based largely (especially the datacontext and the local storage) is based largely on John Papa's recent Pluralsight courses.
In my app, BusUnit = Hero and Dimension = Power (in reference to Ward's example.
Everything seems to be working well when I force the app to fetch data from the server, in that my updates to a business unit's dimensions reflect correctly. The problem I'm facing now is when I navigate away from the page and back again (which gets data from local storage). In this case:
if I previously added a new dimension to a business unit, everything is ok, but
if i previously marked a business unit's dimension for deletion and the save, the dimension still appears for the business unit in question.
this is the controller code that initially gets business units and their dimensions:
function getdboardStructure() {
var busUnitsPromise = datacontextSvc.busUnits.getByDboardConfigId(vm.dboardConfig.id);
var dimensionsPromise = datacontextSvc.dimensions.getByDboardConfigId(vm.dboardConfig.id);
$q.all([busUnitsPromise, dimensionsPromise])
.then(function (values) {
vm.busUnits = values[0];
vm.dims = values[1];
createBusUnitVms();
//vm.currentBusUnitVm = vm.busUnitVms[0]; // not required as using accordion instead of drop-down
vm.hasChanges = false;
});
}
this is the code in my controller that prepares for the save:
function applyBusUnitDimensionSelections(busUnitVm) {
var busUnit = busUnitVm.busUnit;
var mapVms = busUnitVm.dimensionMapVms;
var dimensionHash = createBusUnitDimensionHash(busUnit);
mapVms.forEach(function (mapVm) {
var map = dimensionHash[mapVm.dimension.id];
if (mapVm.selected) {
if (!map) {
datacontextSvc.busUnits.addBusUnitDimension(busUnit, mapVm.dimension)
.then(function () {
});
}
} else {
if (map) {
datacontextSvc.markDeleted(map);
}
}
});
}
this is the code in my controller that executes the save:
function save() {
if (!canSave()) {
return $q.when(null);
}
vm.isSaving = true;
vm.busUnitVms.forEach(applyBusUnitDimensionSelections);
return datacontextSvc.save().then(function (saveResult) {
vm.isSaving = false;
trapSavedDboardConfigId(saveResult); // not relevant to use case
}, function (error) {
vm.isSaving = false;
});
}
this is the code in my repository that add a new busUnitDimension entity:
function addBusUnitDimension(busUnit, dimension) {
var newBusUnitDimension = this.em.createEntity(busUnitDimension);
newBusUnitDimension.busUnitId = busUnit.id;
newBusUnitDimension.dimensionId = dimension.id;
return this.$q.when(newBusUnitDimension);
}
this is my datacontext code for marking an item deleted:
function markDeleted(entity) {
return entity.entityAspect.setDeleted();
}
and finally this is the repository code to get business units and their join table entities:
function getByDboardConfigId(dboardConfigId, forceRefresh) {
var self = this;
var predicate = pred.create('dboardConfigId', '==', dboardConfigId);
var busUnits;
if (self.zStorage.areItemsLoaded('busUnits') && !forceRefresh) {
busUnits = self._getAllLocal(entityName, orderBy, predicate);
return self.$q.when(busUnits);
}
return eq.from('BusUnits')
.expand('BusUnitDimensions')
.where(predicate)
.orderBy(orderBy)
.using(self.em).execute()
.to$q(succeeded, self._failed);
function succeeded(data) {
busUnits = data.results;
self.zStorage.areItemsLoaded('busUnits', true);
self.zStorage.save();
//self.logSuccess('Retrieved ' + busUnits.length + ' business units from server', busUnits.length, true);
return busUnits;
}
}
My departure from John's course examples is that I'm using expand in the function I use to get Business Units from the server, and my hypothesis is that this has something to do with the fact that breeze is going to the server everytime I refresh the page (without clearing cache) instead, and that this also has something to do with the error i'm receiving if I navigate away and then back to the page.
Can anyone offer and suggestions?
Appreciate this was a long time ago and you have probably solved it or moved on but I came up against the same problem recently that took me ages to resolve.
The answer I found is that you have to edit JP's angular.breeze.storagewip.js file.
I contains the names of the entities hard-coded into the file and you will need to change these to match your own entities.
There are two functions where you need to do this, examples below show the changes with the four entities I am using:
function zStorageCore($rootScope, zStorageConfig) {
var storeConfig = zStorageConfig.config;
var storeMeta = {
breezeVersion: breeze.version,
appVersion: storeConfig.version,
isLoaded: {
elementAssets : false,
surveyors : false,
elements : false,
assets : false
}
};
and...
function checkStoreImportVersionAndParseData(importedData) {
if (!importedData) {
return importedData;
}
try {
var data = JSON.parse(importedData);
var importMeta = data[0];
if (importMeta.breezeVersion === storeMeta.breezeVersion &&
importMeta.appVersion === storeMeta.appVersion) {
if (importMeta.isLoaded) {
storeMeta.isLoaded.assets = storeMeta.isLoaded.assets || importMeta.isLoaded.assets;
storeMeta.isLoaded.elements = storeMeta.isLoaded.elements || importMeta.isLoaded.elements;
storeMeta.isLoaded.surveyors = storeMeta.isLoaded.surveyors || importMeta.isLoaded.surveyors;
storeMeta.isLoaded.elementAssets = storeMeta.isLoaded.elementAssets || importMeta.isLoaded.elementAssets;
}
return data[1];
} else {
_broadcast(storeConfig.events.error,
'Did not load from storage because mismatched versions',
{ current: storeMeta, storage: importMeta });
}
} catch (ex) {
_broadcast(storeConfig.events.error, 'Exception during load from storage: ' + ex.message, ex);
}
return null; // failed
}
I solved this by comparing JP's Style Guide course files with his SPA/Angular/Breeze course.

Resources