Backbone - Unable to fetch data from Specified URL - backbone.js

I'm getting the following error even though I'm pretty sure I have specified the URL in my collection:
Uncaught Error: A `url property or function must be specified
Here's my collection:
import $ from 'jquery';
import Backbone from 'backbone';
import ViewModel from './view-model';
import InstancesCollection from '../instances/instances-collection-model';
export default Backbone.Collection.extend({
model: ViewModel,
url: $.createURL('/api/view'),
initialize: (models = []) => {
models.forEach(element => {
element.instances = new InstancesCollection(element.instances);
});
},
parse: (response) => {
return response.views;
}
});
I tried to follow the response given here but in vain. Does anybody know if I'm missing something here?
Just in case you needed to see the model as well, here it is:
import _ from 'lodash';
import Backbone from 'backbone';
import InstancesCollection from '../instances/instances-collection-model';
export default Backbone.Model.extend({
defaults: {
id: null,
name: null,
count: 0,
instances: []
},
initialize: function (models) {
const attributes = Object.assign({}, this.defaults, models);
if (_.isArray(attributes.instances)) {
this.set({instances: new InstancesCollection(attributes.instances)}, {silent: true});
}
},
toJSON: function () {
let json = Object.assign({}, this.attributes);
for (const attr of Object.keys(json)) {
if ((json[attr] instanceof Backbone.Model) || (json[attr] instanceof Backbone.Collection)) {
json[attr] = json[attr].toJSON();
}
}
return json;
}
});
Any help would be appreciated. Thank you.

Related

How do I get the decimal in the right place with mongoose-currency?

I have implemented mongoose-currency in my User model:
const mongoose = require("mongoose");
const { Schema } = mongoose;
require("mongoose-currency").loadType(mongoose);
const Currency = mongoose.Types.Currency;
const userSchema = new Schema({
googleId: String,
paid: { type: Currency },
});
mongoose.model("users", userSchema);
but even if I add toFixed(2) on the client side:
import React, { Component } from "react";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
class Header extends Component {
renderContent() {
switch (this.props.auth) {
case null:
return;
case false:
return (
<li>
<a href='/auth/google'>Login With Google</a>
</li>
);
default:
return [
<li key='1'>Paid: ${this.props.auth.paid.toFixed(2)}</li>,
<li key='2'>
<a href='/api/logout'>Logout</a>
</li>,
];
}
}
I get $1000.00 instead of $10.00, how do I get the decimal point to work without adding two more zeroes?
So I tried this approach:
const mongoose = require("mongoose");
const { Schema } = mongoose;
const userSchema = new Schema({
googleId: String,
paid: { type: Number, get: getPaid },
});
const getPaid = userSchema.path("paid").get(function (p) {
return (p / 100).toFixed(2);
});
mongoose.model("users", userSchema);
but I get the ReferenceError: Cannot access 'getPaid' before initialization
You should define a getter for your schema like so:
userSchema.path('paid').get(function(p) {
return (p / 100).toFixed(2);
});
ADDED:
There is no need to reference your getter like this:
paid: { type: Number, get: getPaid },
Getters work when you try to access the the path. So this is how you should do it:
const userSchema = new Schema({
googleId: String,
paid: { type: Number },
});
userSchema.path("paid").get(function (p) {
return (p / 100).toFixed(2);
});
However, there is a gotcha there: in order for the getter to trigger, you need to explicitly access the path. As such, when you search you collection, you will need to call up the path from the doc that gets returned:
userSchema.findById('5fc9c809fc360d373b3d77b8')
.then(u => {
console.log(u) // <- this will show the original "paid" path
console.log(u.paid) // <- This will give you the formatted "paid" path
})
Just FYI, to do it the way you attempted, you would need to write your code like so (which would accomplish the same thing as describe above):
const userSchema = new Schema({
googleId: String,
paid: { type: Number, get: getPaid },
});
function getPaid(p) {
return (p / 100).toFixed(2);
});
While the solution offered should logically work, it just did not work for me because I would get issues with reference errors regarding initialization and when I would solve that, it would still render ten dollars as $ 1000.00, so I finally came up with a solution that works for me:
import React, { Component } from "react";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
class Header extends Component {
parsedNumber() {
return (this.props.auth.paid / 100).toFixed(2);
}
renderContent() {
switch (this.props.auth) {
case null:
return;
case false:
return (
<li>
<a href='/auth/google'>Login With Google</a>
</li>
);
default:
return [
<li key='1'>Paid: ${this.parsedNumber()}</li>,
<li key='2'>
<a href='/api/logout'>Logout</a>
</li>,
];
}
}
After so much trial and error and colleagues such as codemonkey helping me out, I realized I had no choice but to somehow work on getting those decimal places to show up at the point that the paid property is rendering and so I came up with the above and it works. Now I get $10.00 as opposed to $1000.00.

Passing data from service to angular components

I am reading data from a firebase database and creating some objects based on the data received and pushing the data into a list. But the control goes back to the component before the objects are created or pushed into the list. I am confused to use any life cycle hooks in this approach.
Class Service(){
questions: QuestionsData<any>[]=[];
getQuestions(FormKey: string) {
var dbQuestions = this.af.list('/elements', {
query: {
limitToLast: 200,
orderByChild: 'formid',
equalTo: FormKey
}
})
dbQuestions.subscribe(snapshots=>{
snapshots.forEach(elementData => {
this.questions.push(new TextboxQuestion({
key: elementData.elementname,
label: elementData.displaytext,
value: elementData.elementvalue,
required: false,
order: elementData.sortorder
}))
}
}
}
Can anyone suggest how to consume this data in my component.
As JB Nizet mentioned in the comments, you should not subscribe to the observable and unwrap it in your template as you are currently doing. Angular provides the async pipe to handle that subscription for you. You simply want to map your data to TextBoxQuestion's. You can do that with the following code.
class MyComponent {
questions$: QuestionsData<any>[]=[];
getQuestions(FormKey: string) {
const dbQuestions$ = this.af.list('/elements', {
query: {
limitToLast: 200,
orderByChild: 'formid',
equalTo: FormKey
}
});
this.questions$ = dbQuestions$.map(snapshots =>
snapshots.map(data => new TextBoxQuestion({
key: data.elementname,
// and so on...
});
}
}
If you want to run that when your component initializes, use the OnInit lifecycle hook:
ngOnInit() {
this.getQuestions(/* form key */);
}
And then use the async pipe in your template like this:
<ul>
<li *ngFor="let question of questions$ | async">
{{ question.key }}
</li>
</ul>
Your service should be more or less like this:
import 'rxjs/add/operator/map'
Class Service() {
getQuestions(FormKey: string): Observable<QuestionsData<any>[]> {
return dbQuestions = this.af.list('/elements', {
query: {
limitToLast: 200,
orderByChild: 'formid',
equalTo: FormKey
}
}).map(snapshots=>{
conts questions: QuestionsData<any>[]=[];
snapshots.forEach(elementData => {
questions.push(new TextboxQuestion({
key: elementData.elementname,
label: elementData.displaytext,
value: elementData.elementvalue,
required: false,
order: elementData.sortorder
}))
})
return questions;
})
}
}
And in the component:
serviceInstance.getQuestions(FormKey).subscribe(questions => {
// your code here
})

Angular 2 Load data through server API : data.slice error

Im trying to load the data from my API to custom component using Angular2 ng Smart table plugin.
AS per their documentation (https://github.com/akveo/ng2-smart-table/blob/master/src/app/pages/examples/server/basic-example-load.component.ts)
i have my component like:
import { LocalDataSource } from 'ng2-smart-table';
import { ProductService } from '../../../services/product.service';
export class CategoryItemsComponent implements OnInit {
...
source: LocalDataSource;
constructor(private productService: ProductService,
private flashMessage: FlashMessagesService,
private router: Router,
http: Http) {
this.source = new LocalDataSource();
this.productService.getProductsOncategory(this.categoryid).subscribe((data) => {
this.source.load(data);
});
}
ProductService .ts
getProductsOncategory(category_id) {
let catUrl = "http://localhost:5000/products/getProductsOncategory"
let headers = new Headers();
headers.append('Content-Type', 'application/json');
let catIdObj = JSON.stringify({ category_id: category_id })
return this.http.post(catUrl, catIdObj, { headers: headers })
.map((response: Response) => response.json())
.do(data => console.log(JSON.stringify(data)))
.catch(this.handleError);
}
The above API used in the service function works perfect in my postman.
Now i need to load the dame data from that API into my custom component.
I am getting this error:
ERROR TypeError: this.data.slice is not a function
at LocalDataSource.webpackJsonp.../../../../ng2-smart-table/lib/data-source/local/local.data-source.js.LocalDataSource.getElements (http://localhost:4200/1.chunk.js:22280:30)
at LocalDataSource.webpackJsonp.../../../../ng2-smart-table/lib/data-source/data-source.js.DataSource.emitOnChanged (http://localhost:4200/1.chunk.js:22185:14)
at LocalDataSource.webpackJsonp.../../../../ng2-smart-table/lib/data-source/data-source.js.DataSource.load (http://localhost:4200/1.chunk.js:22105:14)
at LocalDataSource.webpackJsonp.../../../../ng2-smart-table/lib/data-source/local/local.data-source.js.LocalDataSource.load (http://localhost:4200/1.chunk.js:22243:38)
Ok i got it by using like:
source: LocalDataSource;
constructor(private productService: ProductService,
private flashMessage: FlashMessagesService,
private router: Router,
http: Http)
{
this.source = new LocalDataSource();
}
onChange(categoryid) {
this.productService.getProductsOncategory(categoryid).subscribe(data => {
if (data.success) {
this.source.load(data.products);
console.log('Products obtained');
} else {
console.log('Not obtained!');
}
});
}
Had the same problem. It solved when i check all match columns and add the missing in table data. For example i delared a variable
Settings = {
....
columns: {
id: {
title: 'id',
show: false,
type: 'string',
},
name: {
title: 'name',
type: 'string',
},
//compare columns in json response in same variable declaration
//for your data table [source]
}
}
And in second case your table try get data from dataTableSource before full data loading, to avoid this use setTimeout(); method and set more time.
For Example:
getChildData(): Promise<any> {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(this.childsList);
}, 4000);//<= increase this value
});
}
excuse me for my english))

testbed.createComponents ngsyntax error

Hello I am trying to set up karma testing in an angular 2 project however I can't get rid of an error. It was almost always the same, and after using the .catch after createComponents I got the following.
LOG: Error{ngSyntaxError: true, line: 38169, sourceURL:'http://localhost:9876/base/src/test.ts?62c9c9f2f8eb0595c7519c8d7dc8192bb118a027', stack: 'parse#http://localhost:9876/base/src/test.ts?62c9c9f2f8eb0595c7519c8d7dc8192bb118a027:38169:72
_compileTemplate#http://localhost:9876/base/src/test.ts?62c9c9f2f8eb0595c7519c8d7dc8192bb118a027:51920:44
http://localhost:9876/base/src/test.ts?62c9c9f2f8eb0595c7519c8d7dc8192bb118a027:51844:78
forEach#http://localhost:9876/base/src/polyfills.ts?0c8ebfd4331d2badb8d2ce96ff9ff990e8c26a03:1522:12
_compileComponents#http://localhost:9876/base/src/test.ts?62c9c9f2f8eb0595c7519c8d7dc8192bb118a027:51844:26
createResult#http://localhost:9876/base/src/test.ts?62c9c9f2f8eb0595c7519c8d7dc8192bb118a027:51750:37
invoke#http://localhost:9876/base/src/polyfills.ts?0c8ebfd4331d2badb8d2ce96ff9ff990e8c26a03:3039:31
onInvoke#http://localhost:9876/base/src/test.ts?62c9c9f2f8eb0595c7519c8d7dc8192bb118a027:53668:45
onInvoke#http://localhost:9876/base/src/test.ts?62c9c9f2f8eb0595c7519c8d7dc8192bb118a027:54427:47
invoke#http://localhost:9876/base/src/polyfills.ts?0c8ebfd4331d2badb8d2ce96ff9ff990e8c26a03:3038:40
run#http://localhost:9876/base/src/polyfills.ts?0c8ebfd4331d2badb8d2ce96ff9ff990e8c26a03:2789:49
http://localhost:9876/base/src/polyfills.ts?0c8ebfd4331d2badb8d2ce96ff9ff990e8c26a03:3465:60
invokeTask#http://localhost:9876/base/src/polyfills.ts?0c8ebfd4331d2badb8d2ce96ff9ff990e8c26a03:3072:36
onInvokeTask#http://localhost:9876/base/src/test.ts?62c9c9f2f8eb0595c7519c8d7dc8192bb118a027:54454:49
invokeTask#http://localhost:9876/base/src/polyfills.ts?0c8ebfd4331d2badb8d2ce96ff9ff990e8c26a03:3071:48
runTask#http://localhost:9876/base/src/polyfills.ts?0c8ebfd4331d2badb8d2ce96ff9ff990e8c26a03:2839:57
drainMicroTaskQueue#http://localhost:9876/base/src/polyfills.ts?0c8ebfd4331d2badb8d2ce96ff9ff990e8c26a03:3232:42
invoke#http://localhost:9876/base/src/polyfills.ts?0c8ebfd4331d2badb8d2ce96ff9ff990e8c26a03:3138:44
timer#http://localhost:9876/base/src/polyfills.ts?0c8ebfd4331d2badb8d2ce96ff9ff990e8c26a03:4160:34', __zone_symbol__currentTask: ZoneTask{_zone: Zone{_properties: ..., _parent: ..., _name: ..., _zoneDelegate: ...}, runCount: 0, _zoneDelegates: null, _state: 'notScheduled', type: 'microTask', source: 'Promise.then', data: undefined, scheduleFn: undefined, cancelFn: null, callback: function () { ... }, invoke: function () { ... }}}
I am not sure whether someone is capable of making something of this. My source code is below.
import { async, ComponentFixture, TestBed } from '#angular/core/testing';
import { PlumberAcceptedComponent } from './plumber-accepted.component';
import { DataProvider } from "../../../providers/data.provider";
import { OrderService } from "../order.service";
import { Router } from "#angular/router";
import { AccountProvider } from "../../../providers/account.provider";
import {MockRouter} from '../../../mock';
import * as firebase from 'firebase';
describe('PlumberAcceptedComponent', () => {
let component: PlumberAcceptedComponent;
let fixture: ComponentFixture<PlumberAcceptedComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [PlumberAcceptedComponent],
imports: [ ],
providers: [{provide: Router, useClass:MockRouter},
DataProvider,
OrderService,
AccountProvider
]
})
.compileComponents().catch((err)=>{console.log(err);});
}));
it('should be created', async(() => {
console.log("fdasjklfdjaklfdajfklasdjfklasdjfklasdjklfsdjklfdsjafkldsfasd");
TestBed.compileComponents().then(() => {
console.log(" fjasdklfjasdklfjdasklfjasd");
const fixture = TestBed.createComponent(PlumberAcceptedComponent);
// Access the dependency injected component instance
const app = fixture.componentInstance;
// Access the element
const element = fixture.nativeElement;
// Detect changes as necessary
fixture.detectChanges();
expect(app).toBeTruthy();
}).catch((err)=>{console.log(err);});
}));
});

How should flux handle routing?

I'm fairly new to React and even more new to flux and i'm having troubles finding info on Google about how to handle routing and flux.
I'm using the Meteor stack and the router (FlowRouter) has an imperative API for transitioning routes using FlowRouter.go('routeName, params).
Should I create a Link component that triggers an action and the action creator calls the this FlowRouter.go method?
Also it has a reactive API for the params so I can watch it and trigger an action if something changes (so stores can update).
An approach I took with a recent project while experimenting with Flux was to make the routing layer just another store. I made a Folder that contained React View Component File, Router Store and Router Actions. I am Providing The source Below:
React View File:
var React = require('react');
var storeMixin = require('project/shared/helpers/storeMixin');
var RouterStore = require('../RouterStore');
module.exports = React.createClass({
mixins: [storeMixin(RouterStore)],
getInitialState: function () {
return {RouterStore: RouterStore};
},
getComponentClass: function (route) {
switch (route) {
case 'help':
return require('project/app/components/Help');
default:
return require('project/FrontPage/FrontPage');
}
},
render: function () {
var props = {
route: this.state.RouterStore.get('route'),
routeParams: this.state.RouterStore.get('params')
};
var Component = this.getComponentClass(props.route);
return <Component {...props} />;
}
});
The Store File:
var Backbone = require('backbone');
var Store = require('project/shared/libs/Store');
var conf = require('./settings');
var constants = require('./constants');
class RouterModel extends Store.Model {
constructor() {
this.defaults = {
route: conf.ROUTE_DEFAULT,
params: []
};
super();
}
initialize() {
this._router = new AppRouter(this, conf.ROUTE_ROUTES);
}
handleDispatch(payload) {
switch (payload.actionType) {
case constants.ROUTE_NAVIGATE:
this._router.navigate(payload.fragment, {
trigger: payload.trigger,
replace: payload.replace
});
break;
}
}
}
class AppRouter extends Backbone.Router {
initialize(store, routes) {
this.store = store;
var route, key;
for (key in routes) {
if (routes.hasOwnProperty(key)) {
route = routes[key];
this.route(key, route, function(/* route, args... */) {
this.emitRouteAction.apply(this, arguments);
}.bind(this, route));
}
}
// catch all non-matching urls
Backbone.history.handlers.push({
route: /(.*)/,
callback: function() {
store.set({
route: constants.ROUTE_DEFAULT,
params: []
});
}
});
Backbone.$(document).on("ready", function() {
Backbone.history.start();
});
}
emitRouteAction(/* route, args... */) {
this.store.set({
route: arguments[0],
params: [].slice.call(arguments, 1)
});
}
}
module.exports = new RouterModel();
The Actions File:
var constants = require('./constants');
var dispatch = require('project/shared/helpers/dispatch');
var _ = require('underscore');
module.exports = {
navigate: function(fragment, trigger, replace) {
dispatch(constants.ROUTE_NAVIGATE, {
fragment: fragment,
trigger: _.isUndefined(trigger) ? true : trigger,
replace: _.isUndefined(replace) ? true : replace
});
}
};

Resources