How to pass a parameter to Collection parse? backbone.js - javascript

How could one pass a parameter through the parse/fetch function?
I want to pass the variable VARIABLE_PARAMETER in the lower Initialize-part.
Otherwise I have to write three mostly identical Collections.
Thank you for you help.
app.js
//--------------
// Collections
//--------------
DiagnoseApp.Collections.Param1_itemS = Backbone.Collection.extend({
model: DiagnoseApp.Models.Param1_item,
url: 'TestInterface.xml',
parse: function (data) {
var parsed = [];
$(data).find(/*VARIABLE_PARAMETER*/).find('PARAMETER').each(function (index) {
var v_number = $(this).attr('Number');
var v_Desc_D = $(this).attr('Desc_D');
parsed.push({ data_type: v_data_type, number: v_number, Desc_D: v_Desc_D});
});
return parsed;
},
fetch: function (options) {
options = options || {};
options.dataType = "xml";
return Backbone.Collection.prototype.fetch.call(this, options);
}
});
This is the way I initialize the app:
//--------------
// Initialize
//--------------
var VARIABLE_PARAMETER = "OFFLINE";
var offline_Collection = new DiagnoseApp.Collections.Param1_itemS();
var offline_Collection_View = new DiagnoseApp.Views.Param1_itemS({collection: offline_Collection});
//VARIABLE_PARAMETER has to be passed here in fetch I guess ??
offline_Collection.fetch({
success: function() {
console.log("JSON file load was successful", offline_Collection);
offline_Collection_View.render();
},
error: function(){
console.log('There was some error in loading and processing the JSON file');
}
});

The fetch method accepts an option argument : http://backbonejs.org/#Collection-fetch
The parse method also accepts an option argument: http://backbonejs.org/#Collection-parse
These objects are actually the same. So you may write:
parse: function (data, options) {
var parsed = [];
$(data).find(options.variableParameter).find('PARAMETER').each(function (index) {
var v_number = $(this).attr('Number');
var v_Desc_D = $(this).attr('Desc_D');
parsed.push({ data_type: v_data_type, number: v_number, Desc_D: v_Desc_D});
});
return parsed;
},

Not sure I understand your question, but if you want to "pass a parameter" from fetch to parse, and if that parameter value doesn't change for a given collection, you could just store it in the collection. You could pass the parameter to fetch as an additional property in options:
fetch: function (options) {
options = options || {};
options.dataType = "xml";
this.variableParameter = options.variableParameter;
return Backbone.Collection.prototype.fetch.call(this, options);
},
And then simply retrieve it
parse: function (data) {
// do something useful with this.variableParameter
// ...
}

Related

Unable to access knockout observable array item

I fetch data from web api and push the data into observable array. I would like to make the observable array item to be observable. However, it seems that i could not access the object if i make it observable.
function KnockoutViewModel() {
var self = this;
self.ProfileList = ko.observableArray([]);
self.GetProfile = function() {
$.ajax({
type: 'GET',
success: function() {
$.each(data.ProfileList, function (index, value) {
self.ProfileList.push(value);
alert(self.ProfileList()[index].Name) // success
}
}
});
}
self.GetProfile();
}
function KnockoutViewModel() {
var self = this;
self.ProfileList = ko.observableArray([]);
self.GetProfile = function() {
$.ajax({
type: 'GET',
success: function() {
$.each(data.ProfileList, function (index, value) {
self.ProfileList.push(ko.observable(value));
alert(self.ProfileList()[index].Name) // fail. Object does not support property or method 'Name'
}
}
});
}
self.GetProfile();
}
you are directly pushing object (by making it observable) into observableArray does it sound right ? Nah (you may want to make Name as observable i believe) . Tough you can get the output by doing something like this self.ProfileList()[index]().Name check here
Preferred way :
viewModel:
function convert(data) {
this.Name = ko.observable(data.Name)
this.place = ko.observable(data.place)
this.age = ko.observable(data.age)
}
function KnockoutViewModel() {
var self = this;
self.ProfileList = ko.observableArray([]);
self.GetProfile = function () {
var data = [{
'Name': 'Super',
'place': 'Ind',
'age': 25
}, {
'Name': 'Cool',
'place': 'Aus',
'age': 15
}]
//Manual way with function defined
//self.ProfileList(ko.utils.arrayMap(data, function (value) {
// return new convert(value)
//}))
//Using Mapping Plugin
ko.mapping.fromJS(data,{},self.ProfileList)
}
self.GetProfile();
}
ko.applyBindings(new KnockoutViewModel());
working sample here
Try to use the mapping module:
self.ProfileList.push(ko.mapping.fromJS(value));
This will automatically wrap value's properties in knockout observables.

how to access changed attributes after fetch? backbone.js

I'm using this code to fetch a model from a server:
var id = args.model.get('id');
var options = {
action: 'getSubscriber',
address: args.model.get('address'),
silent: true
};
new Subscriber({ id: id }, options).fetch({
success: function(model, response) {
console.log(response);
console.log(model);
}
});
the response object contains all the data I need whereas model stores the data not as its direct attributes but as changed object. Is it wrong?
Usually I access model attributes with help of model.get('name') call. How do I access fresh attributes in that case? Should it be model.changed.thePropertyIwantToAccess?
You can use this change event
this.model.on('change', function () {
var changedAttributes = this.model.changedAttributes();
//Process the changed attributes
}, this);
Bind this events in the initialize function of the View
Ended up with this:
var Subscriber = Backbone.Model.extend({
defaults: {
id: null,
name: null,
status: null
// ...
},
initialize: function(attributes, options) {
var _this = this;
this.options = options || {};
this.on('change', function() {
_this.set(_this.changedAttributes()['0']);
});
}
// ...

CanJS add custom MODEL method

I want to add another function to get result from a CanJs Model
i Have something like this:
VideomakerModel = can.Model({
id:'ID',
findAll: 'GET /videomakers/',
findNear: function( params ){
return $.post("/get_near_videomakers/",
{address:params.address},
undefined ,"json")
}
},{});
VideomakerModel.findNear({address : "Milan"}, function(videomakers) {
var myList = new VideomakerControl($('#accordionVm'), {
videomakers : videomakers,
view: 'videomakersList'
});
});
If I name the method findAll it works correctly,
otherwise naming it findNear it never reach the callback
should I extend MODEL is some way?? is there a way of add a function like FindAll?
thank you very much
CanJS only adds the conversion into a Model instance for the standard findOne, findAll etc. Model methods. You will have to do that yourself in your additional implementation by running the result through VideoMaker.model (for a single item) or VideoMaker.models (for multiple items):
VideomakerModel = can.Model({
id:'ID',
findAll: 'GET /videomakers/',
findNear: function( params ) {
var self = this;
return $.post("/get_near_videomakers/", {
address:params.address
}, undefined ,"json").then(function(data) {
return self.model(data);
});
}
},{});
If I understand the question, it is necessary to do so:
VideomakerModel = can.Model({
id:'ID',
findAll: 'GET /videomakers/'
},
{
findNear: function(options, success){
can.ajax({
url: "/get_near_videomakers/",
type: 'POST',
data: options,
success: success
})
}
})
var myList = new VideomakerControl({});
myList.findNear({address:params.address}, function(resulrRequest){
//success
} )

How to set data in an action using IronRouter on Meteor?

How can I set additional data in an action function in a Meteor Application that uses IronRouter ? See comments in emailWelcome and emailContract functions below...
Code:
EmailController = RouteController.extend({
template: 'emailPage',
waitOn: function() {
return [
Meteor.subscribe('customers'),
];
},
data: function() {
var request = Requests.findOne(this.params._id);
if (!request)
return;
var customer = Customers.findOne({'_id': request.customerId});
if (!customer)
return;
return {
sender: Meteor.user(),
recipient: Customers.findOne({_id:Session.get('customerId')})
};
},
emailWelcome: function() {
// Set var in the context so that emailTemplate = 'welcomeEmail' here
this.render('emailPage');
},
emailContract: function() {
// Set var in the context so that emailTemplate = 'contractEmail' here
this.render('emailPage');
}
});
You can get access to the data with this.getData() in your action functions:
emailWelcome: function() {
var data = this.getData(); // get a reference to the data object
data.emailTemplate = 'welcomeEmail';
this.render('emailPage');
},
emailContract: function() {
var data = this.getData(); // get a reference to the data object
data.emailTemplate = 'contractEmail';
this.render('emailPage');
}
be careful not to call this.data(), as that will regenerate the
data instead of getting you a reference to the already generated data
object.
also be careful not to call this.setData(newData) within an action as that will invalidate the old data object, initiating a reactivity reload, and lead to an infinite loop!

Binding view with javascript knockout

Here i have my get method that gets the data that i want to return in order to bind it with the view page. I am having trouble wrapping my head to how i could bind this information to the view.
Get Method:
var getRoster = function () {
Ajax.Get({
Url: ....,
DataToSubmit: {id: properties.Id },
DataType: "json",
OnSuccess: function (roleData, status, jqXHR) {
console.log("roles:", roleData.length);
Ajax.Get({
Url: ...,
DataToSubmit: { pageNumber: 1, id: properties.Id },
DataType: "json",
OnSuccess: function (userData, status, jqXHR) {
for (var x in roleData)
{
var role = roleData[x];
console.log(role);
for (var y in userData)
{
var user = userData[y];
if (user.ContentRole == role.ContentRole)
{
rosterViewModel.PushUser(new userViewModel(user));
console.log(user);
}
}
roleTypesViewModel.PushRole(new roleViewModel(role));
}
}
});
}
});
rosterViewModel.PushUser = function (user) {
viewModel.RosterUsers.push(new userViewModel(user));
};
roleTypesViewModel.PushRole = function (role) {
viewModel.RosterRoleTypes.push(new roleViewModel(role));
}
var userViewModel = function (data) {
var _self = this;
_self.ID = ko.observable(data.ID);
_self.Name = ko.observable(data.Name);
_self.Email = ko.observable(data.Email);
_self.ContentRole = ko.observable(data.ContentRole);
};
var roleViewModel = function (data) {
var _self = this;
_self.ContentRole = ko.observable(data.ContentRole);
_self.RoleName = ko.observable(data.RoleName);
_self.RoleRank = ko.observable(data.RoleRank);
_self.UserCount = ko.observable(data.UserCount);
};
var viewModel = {
RosterRoleTypes: ko.observableArray([]),
RosterUsers: ko.observableArray([])
};
View:
<div id="gridView" data-bind="foreach: RosterRoleTypes">
<h3 class="roleHeader"><span data-bind="text:RoleName"></span>
<span class="userCount">(<span data-bind="text:UserCount"></span>)</span>
</h3>
<div data-bind="template: { name: 'grid', foreach: RosterUsers}">
</div>
</div>
How can i bind my data to display in my view?
If you are trying to bind multiple areas of your page to different view models, that is possible by passing in an additional parameter to your ko.applyBindings() method that you call. Your problem is that you are mixing models and view models and using them improperly. If you want to have one view model adjust your code to include all of the functions of your view model and set your models as models instead of viewmodels -
function rosterViewModel() {
var self = this;
self.RosterRoleTypes = ko.observableArray([]),
self.RosterUsers = ko.observableArray([])
self.PushUser = function (user) {
viewModel.RosterUsers.push(new userModel(user));
};
self.PushRole = function (role) {
viewModel.RosterRoleTypes.push(new roleModel(role));
};
self.getRoster = function () {
Ajax.Get({
Url: ....,
DataToSubmit: {id: properties.Id },
DataType: "json",
OnSuccess: function (roleData, status, jqXHR) {
Ajax.Get({
Url: ...,
DataToSubmit: { pageNumber: 1, id: properties.Id },
DataType: "json",
OnSuccess: function (userData, status, jqXHR) {
for (var x in roleData)
{
var role = roleData[x];
for (var y in userData)
{
var user = userData[y];
if (user.ContentRole == role.ContentRole)
{
self.PushUser(new userModel(user));
}
}
self.PushRole(new roleModel(role));
}
}
});
}
});
}
var userModel = function (data) {
var _self = this;
_self.ID = ko.observable(data.ID);
_self.Name = ko.observable(data.Name);
_self.Email = ko.observable(data.Email);
_self.ContentRole = ko.observable(data.ContentRole);
};
var roleModel = function (data) {
var _self = this;
_self.ContentRole = ko.observable(data.ContentRole);
_self.RoleName = ko.observable(data.RoleName);
_self.RoleRank = ko.observable(data.RoleRank);
_self.UserCount = ko.observable(data.UserCount);
};
ko.applyBindings(new rosterViewModel());
This assumes you want to use a single view model for your view. If you are combining multiple content areas that should be bound separately you can create two view models and merge them as shown in this question - KnockOutJS - Multiple ViewModels in a single View - or you could also bind them separately by passing in an additional parameter to the ko.applyBindings() method as showm here - Example of knockoutjs pattern for multi-view applications
All of the data that you want to bind to UI will be properties of your viewmodel as KO observable or observable arrays. Once the view model is created and its members are assigned with data(callbacks in your case), you need to apply bindings using ko.applyBindinds so that the data is bound to UI. In your case the last AJAX success callback seems to be the appropriate place.
Also your HTML makes using of template bindings however apparently there is no template defined with name 'grid'. Check on this.
Knockout tutorial link http://learn.knockoutjs.com/#/?tutorial=intro
Add
ko.applyBindings(viewModel);
somewhere in your application.

Categories