Check input value against an array - backbone.js

I am using this plugin for my autocomplete form:
http://www.planbox.com/blog/news/updates/jquery-autocomplete-plugin-for-backbone-js.html
Instead of checking only one item, as in the code below (if (inputVal == 'bakaxel')),
I would like to check the selected value against the entire collection
var collection = new Backbone.Collection([
{id:"AB", name:"Alberta"},
{id:"AD", name:"Album"},
{id:"BA", name:"barn"},
{id:"BC", name:"bak"},
{id:"BD", name:"baby"},
{id:"BE", name:"band"},
{id:"BF", name:"bakaxel"},
{id:"BG", name:"batteri"},
{id:"BH", name:"barbie"},
{id:"MB", name:"Manitoba"},
{id:"AP", name:"Armed Forces Pacific"}
]);
$('input.search').autocomplete({
collection: collection,
attr: 'name',
noCase: true,
ul_class: 'search_options tr_list',
ul_css: {'z-index':1234}
});
$('input.search').each(function(){
$(this).blur(function(){
var inputVal = $('input.search').val();
if (inputVal == 'bakaxel') {
$('#search_result_page').load('searchResult.html');
$('#searchPage').addClass('hidden');
}
});
});
I tried this, but I'd rather not create the ar array again, just use the backbone collection:
$('input.search').each(function(){
$(this).blur(function(){
var inputVal = $('input.search').val();
var ar = ["Alberta", "Album", "barn", "bak", "baby", "band", "bakaxel", "batteri", "barbie", "Manitoba", "Armed Forces Pacific"];
if (jQuery.inArray(inputVal, ar) != -1) {
$('#search_result_page').load('searchResult.html');
$('#searchPage').addClass('hidden');
}
});
});

Backbone proxies Underscore functions and most notably in your case http://underscorejs.org/#where
where _.where(list, properties)
Looks through each value in the list, returning an array of all the values that contain all of the
key-value pairs listed in properties.
Your test could be written as
var matches = collection.where({
name: inputVal
});
if (matches.length>0) {
...
}
Or as #mu suggested in the comments, you could just check the existence of the input with http://underscorejs.org/#find
var found = collection.find(function(model) {
return model.get('name') === inputVal
});
if (found) {
...
}

Related

excluding from an object angular ng-change

Hello guys i am trying to clear my ng-model when i fire my change function but my problem that i don't want to delete all i want to exclude one item in the object.
function change() {
if (vm.location.type) {
angular.forEach(vm.location, function (value, index) {
delete vm.location;
});
}
}
so i don't want to delete the
vm.location.type
my
vm.location
has
vm.location.boundaries;
vm.location.region;
vm.location.address;
vm.location.name;
vm.location.nonVisitingRadius;
vm.location.visitingRadius;
See the code below,
var obj = { a:123, b:123, c:123 }
delete obj.a;
Hence obj will be like this {b:123, c:123}
Note: Dont need any for loop to delete property from object
Updated Answer:
var obj= {
a: 'aaa',
b: 'bbb',
c: 'ccc',
d: 'ddd'
};
var removeObj = function(obj, props) {
for(var i = 0; i < props.length; i++) {
if(obj.hasOwnProperty(props[i])) {
delete obj[props[i]];
}
}
};
removeObj (obj, ["a", "d"]);
i don't know if i understand correctly what you're asking, but if you want to clear all the fields of your object preserving only type and preserving the reference of the object with plain javascirpt (no libraries), loop over the fields and check if the i field is equal to type.
for(var i in model.location){
if(i !== 'type')
delete model[i];
}
with underscore.js you could define a default model like:
var defaultModel = {
location: {
region: '',
address: '',
name: '',
nonVisitingRadius: '',
visitingRadius: '',
type: 'defaultvalue'
}
}
and when ng-change is triggered inside the function
_.extend(model, defaultModel);
that will keep the default value for type and clear all the others.
You can do it this with a temporary object :
let tempLocation = {};
tempLocation.type = $scope.location.type;
$scope.location = tempLocation;

Ember array serialization

I'm adding objects to an array property of a model, then saving it. When I look at the outgoing request, the property in question is always an empty array.
My custom serializer (extending Ember.RESTSerializer) has this:
DS.ArrayTransform = DS.Transform.extend(
{
deserialize: function(serialized)
{
return (Ember.typeOf(serialized) == "array") ? serialized : [];
},
serialize: function(deserialized)
{
var type = Ember.typeOf(deserialized);
if (type == 'array')
{
return [{foo:'bar'}];
// return deserialized;
}
else if (type == 'string')
{
return deserialized.split(',').map(function(item)
{
return item.trim();
});
}
else
{
return [];
}
}
});
App.register("transform:array", DS.ArrayTransform);
As you can see I've tried passing back an arbitrary array with an object in it, but even then the array always comes out as empty. In the app I create the record like this:
var post = this.store.createRecord('explorePost', {
title: content.get('title'),
text: content.get('text'),
postDate: content.get('postdate'),
publishDate: content.get('publishDate'),
published: content.get('published'),
postType: content.get('postType'),
link: content.get('link,'),
projectDownloads: [],
// projectDownloads: this.model.get('projectDownloads'),
projectLinks: content.get('projectLinks'),
});
then add the objects like this:
this.model.get('projectDownloads').forEach(function (_download) {
console.log('pushing download', _download);
post.get('projectDownloads').pushObject(_download);
});
I can confirm that at time of saving, the post object has a projectDownloads array with one object in it. No matter what I do I can't seem to get it to spit out the contents when it saves. It's definitely going into the custom serializer, and detects it as an array, but you can see something else seems to be overriding it.
Can anyone tell me what I'm doing wrong? My model setup is below:
App.ExplorePost = DS.Model.extend(
{
title: DS.attr('string'),
text: DS.attr('string'),
link: DS.attr('string'),
postDate: DS.attr('momentdate'),
publishDate: DS.attr('momentdate'),
user: DS.belongsTo('user',{async:true}),
postType: DS.attr('string'),
activity: DS.belongsTo('activity',{ inverse: 'explorePost', async:true}),
comments: DS.hasMany('comment',{ inverse: 'explorePost', async: true }),
// projectDownloads: DS.hasMany('projectDownload',{ inverse: 'explorePost'}),
projectDownloads: DS.attr('array'),
// projectLinks: DS.hasMany('projectLink',{ inverse: 'explorePost'}),
projectLinks: DS.attr('string'),
published: DS.attr('boolean', {defaultValue: true}),
// tags: DS.hasMany('tag')
sortdate: function()
{
var datestr = Ember.isEmpty(this.get('postDate')) ? '' : moment(this.get('postDate')).format('YYYYMMDDHHmm');
var fn = (datestr + '____________').slice(0, 12);
return fn;
}.property('postDate')
});
There's no built in DS.attr('array') and a naive implementation would probably not know how to serialize ember-data objects found inside. Did you intend to leave that in there? If you swap it back to the relationships you've commented out and change projectDownloads to work with the promise:
this.model.get('projectDownloads').then(function(downloads) {
downloads.forEach(function(_download){
post.get('projectDownloads').pushObject(_download);
});
});
This should work jsut fine. I put together something nearly identical the other day. http://emberjs.jsbin.com/zolani/3/edit?html,css,js,output
if you array not contain complex object, like array of string, you can use DS.attr(), it will work.

Nodejs async data duplication

I'm having some problems with one async process on nodejs.
I'm getting some data from a remote JSON and adding it in my array, this JSON have some duplicated values, and I need check if it already exists on my array before add it to avoid data duplication.
My problem is when I start the loop between the JSON values, the loop call the next value before the latest one be process be finished, so, my array is filled with duplicated data instead of maintain only one item per type.
Look my current code:
BookRegistration.prototype.process_new_books_list = function(data, callback) {
var i = 0,
self = this;
_.each(data, function(book) {
i++;
console.log('\n\n ------------------------------------------------------------ \n\n');
console.log('BOOK: ' + book.volumeInfo.title);
self.process_author(book, function() { console.log('in author'); });
console.log('\n\n ------------------------------------------------------------');
if(i == data.length) callback();
})
}
BookRegistration.prototype.process_author = function(book, callback) {
if(book.volumeInfo.authors) {
var author = { name: book.volumeInfo.authors[0].toLowerCase() };
if(!this.in_array(this.authors, author)) {
this.authors.push(author);
callback();
}
}
}
BookRegistration.prototype.in_array = function(list, obj) {
for(i in list) { if(list[i] === obj) return true; }
return false;
}
The result is:
[{name: author1 }, {name: author2}, {name: author1}]
And I need:
[{name: author1 }, {name: author2}]
UPDATED:
The solution suggested by #Zub works fine with arrays, but not with sequelize and mysql database.
When I try to save my authors list on the database, the data is duplicated, because the system started to save another array element before finish to save the last one.
What is the correct pattern on this case?
My code using database is:
BookRegistration.prototype.process_author = function(book, callback) {
if(book.volumeInfo.authors) {
var author = { name: book.volumeInfo.authors[0].toLowerCase() };
var self = this;
models.Author.count({ where: { name: book.volumeInfo.authors[0].toLowerCase() }}).success(function(count) {
if(count < 1) {
models.Author.create(author).success(function(author) {
console.log('SALVANDO AUTHOR');
self.process_publisher({ book:book, author:author }, callback);
});
} else {
models.Author.find({where: { name: book.volumeInfo.authors[0].toLowerCase() }}).success(function(author) {
console.log('FIND AUTHOR');
self.process_publisher({ book:book, author:author }, callback);
});
}
});
// if(!this.in_array(this.authors, 'name', author)) {
// this.authors.push(author);
// console.log('AQUI NO AUTHOR');
// this.process_publisher(book, callback);
// }
}
}
How can I avoid data duplication in an async process?
This is because you are comparing different objects and result is always false.
Just for experiment type in the console:
var obj1 = {a:1};
var obj2 = {a:1};
obj1 == obj2; //false
When comparing objects (as well as arrays) it only results true when obj1 links to obj2:
var obj1 = {a:1};
var obj2 = obj1;
obj1 == obj2; //true
Since you create new author objects in each process_author call you always get false when comparing.
In your case the solution would be to compare name property for each book:
BookRegistration.prototype.in_array = function(list, obj) {
for(i in list) { if(list[i].name === obj.name) return true; }
return false;
}
EDIT (related to your comment question):
I would rewrite process_new_books_list method as follows:
BookRegistration.prototype.process_new_books_list = function(data, callback) {
var i = 0,
self = this;
(function nextBook() {
var book = data[i];
if (!book) {
callback();
return;
}
self.process_author(book, function() {
i++;
nextBook();
});
})();
}
In this case next process_author is being called not immediately (like with _.each), but after callback is executed, so you have consequence in your program.
Not sure is this works though.
Sorry for my English, I'm not a native English speaker

Backbone custom model get

I'd like one of my getters to return a minimum value of the model's collection, is it possible to have a model getter function? Reason I need this is so I can easily have my models rendered in a template using toJSON.
Are these minimum values just defaults to fill in, if there is nothing else?
If so. you can define the defaults on the model
var model = Backbone.Model.extend({
defaults: {
attrA: 'attr a default',
attrB: 'attr b default'
}
});
Apart from the defaults you can override the get method if you need more control.
var MyModel = Backbone.Model.extend({
get: function (attr) {
if (attr === 'my_attribute')
{
return this.getMyAttribute();
}
return Backbone.Model.prototype.get.call(this, attr);
},
getMyAttribute: function() {
var result = Backbone.Model.prototype.get.call(this, attr);
if (typeof result === "undefined" || result < 0) return 0;
return result;
}
});

passing data to a collection in backbone

So I am trying storing product types from a json file before trying to add them to a collection but am getting some strange results (as in I dont fully understand)
on my router page i setup a variable for cached products as well as product types
cachedProductTypes: null,
productType : {},
products : {},
getProductTypes:
function(callback)
{
if (this.cachedProductTypes !== null) {
return callback(cachedProductTypes);
}
var self = this;
$.getJSON('data/product.json',
function(data)
{
self.cachedProductTypes = data;
callback(data);
}
);
},
parseResponse : function(data) {
result = { prodTypes: [], products: [] };
var type;
var types = data.data.productTypeList;
var product;
var i = types.length;
while (type = types[--i]) {
result.prodTypes.push({
id: type.id,
name: type.name,
longName: type.longName
// etc.
});
while (product = type.productList.pop()) {
product.productTypeId = type.id,
result.products.push(product);
}
};
this.productType = result.prodTypes;
console.log( "dan");
this.products = result.products;
},
showProductTypes:function(){
var self = this;
this.getProductTypes(
function(data)
{
self.parseResponse(data);
var productTypesArray = self.productType;
var productList=new ProductsType(productTypesArray);
var productListView=new ProductListView({collection:productList});
productListView.bind('renderCompleted:ProductsType',self.changePage,self);
productListView.update();
}
);
}
when a user goes to the show product types page it runs the showProductsType function
So I am passing the products type array to my collection
on the collection page
var ProductsType=Backbone.Collection.extend({
model:ProductType,
fetch:function(){
var self=this;
var tmpItem;
//fetch the data using ajax
$.each(this.productTypesArray, function(i,prodType){
tmpItem=new ProductType({id:prodType.id, name:prodType.name, longName:prodType.longName});
console.log(prodType.name);
self.add(tmpItem);
});
self.trigger("fetchCompleted:ProductsType");
}
});
return ProductsType;
now this doesnt work as it this.productTypesArray is undefined if i console.log it.
(how am I supposed to get this?)
I would have thought I need to go through and add each new ProductType.
the strange bit - if I just have the code
var ProductsType=Backbone.Collection.extend({
model:ProductType,
fetch:function(){
var self=this;
var tmpItem;
//fetch the data using ajax
self.trigger("fetchCompleted:ProductsType");
}
});
return ProductsType;
it actually adds the products to the collection? I guess this means I can just pass an array to the collection and do not have to add each productType?
I guess this means I can just pass an array to the collection and do not have to add each productType?
Yes, you can pass an array to the collection's constructor, and it will create the models for you.
As far as your caching code, it looks like the problem is here:
if (this.cachedProductTypes !== null) {
return callback(cachedProductTypes);
}
The callback statement's argument is missing this - should be return callback(this.cachedProductTypes).

Resources