knockout mapping from JS with extra proeprties - javascript

I have this jSON structure.
{
"customer": {
"idcustomer": 2,
"name": "test_2",
"vat": "test_vat_2",
"obs": "obs_2",
"deleted": 0
},
"addresses": [
{
"idaddress": 9,
"street": "street_2_9",
"number": "number_2_9",
"country": "country_2_9",
"default": true,
"label": "labe_2_9",
"deleted": 0
},
{
"idaddress": 10,
"street": "1",
"number": "number_2_9",
"country": "country_2_10",
"default": false,
"label": "label_2_10",
"deleted": 0
}
],
"contacts": []
}
With knockout mapping plugin I am able to generate a knockout observable object. However, when trying to add extra properties to the object using the mapping parameter I find some issues. The goal is to add "SelectedAddress" to the main object and in each address a "defaultLabel" observabale.
Currently i have this mapping structure to add the property to the address children:
var mapping = {
'addresses': {
create: function (options) {
return (new (function () {
this.defaultLabel= ko.computed(function () {
return (this.default() == 0) ? "" : this.label();
}, this);
ko.mapping.fromJS(options.data, {}, this);
})());
}
},
}
and this to add the "SelectedAddress" to the main JSON:
create: function (options) {
return new function () {
var model = ko.mapping.fromJS(options.data, {}, this);
// Direccion
model.direccionSeleccionada = ko.observable();
model.getDireccion = ko.computed({
read: function() {
if (model.direccionSeleccionada() != null) {
return model.direccionSeleccionada();
} else {
return [{
idaddress: -1,
street : '',
number: '',
country: '',
default: '',
label: '',
deleted: '',
}];
}
},
write: function(value) {
self.direccionSeleccionada(value);
},
owner: self
});
}
}
I can not find a way to have them both
Ideas?
Thank you

I figured it out. Just for someone; Just as simple as when generatint he mapping of "addresses", add inside another mapping for it.
var mapping = {
create: function (options) {
return new function () {
var model = ko.mapping.fromJS(options.data, {
'adresses': {
create: function (options) {
return (new(function () {
this.labelDefault= ko.computed(function () {
return (this.default() == 0) ? "" : this.label();
}, this);
ko.mapping.fromJS(options.data, {}, this);
})( /* call the ctor here */ ));
}
},
}, this);
model.direccionSeleccionada = ko.observable();
model.getDireccion = ko.computed({
read: function () {
if (model.selectedAddress() != null) {
return model.selectedAddress();
} else {
return [{
idaddress: -1,
street: '',
number: '',
country: '',
default: '',
label: '',
deleted: ''
}];
}
},
write: function (value) {
self.selectedAddress(value);
},
owner: self
});
}
}
}
Thank you!

Related

Computed property in a v-loop workaround

I'm trying to make the code below work knowing that computed properties can't take parameters. Do you have any idea ? I'm exploring the use of watchers on functions but I was wondering if there was not an easier solution to do this.
var app = new Vue({
el: '#app',
data() {
return {
sessions: {
"156": {
tickets: {
"01": {
available: true,
},
"02": {
available: false,
},
}
},
},
tickets: {
"01": {
attr: "somestring",
},
"02": {
attr: "someotherstring",
},
},
},
};
},
computed: {
sessionTickets(session) {
let _this = this;
let sessionTickets = {};
$.each(_this.session.tickets, function(ticketId, sessionTicket) {
if(sessionTicket.available) {
sessionTickets[ticketId] = _this.tickets[ticketId];
}
});
return sessionTickets;
},
},
});
<div v-for="session in sessions">
<div v-for="sessionTicket in sessionTickets(session)">
{{ sessionTicket.attr }}
</div>
</div>
Thanks to "WallOp" for making me realize that my computed property is in a sessions loop and so it can normally become a class method and be refreshed on sessions refresh !
I think you can use computed property. Just filter tickets of sessions. Like this:
var app = new Vue({
el: '#app',
data() {
return {
sessions: {
"156": {
tickets: {
"01": {
available: true,
},
"02": {
available: false,
},
}
},
},
tickets: {
"01": {
attr: "somestring",
},
"02": {
attr: "someotherstring",
},
},
},
};
computed: {
filteredSessions() {
return this.sessions.map( session => {
let tickets = {};
for(key in session.tickets) {
if(session.tickets[key].available && this.tickets.hasOwnProperty(key)) {
tickets[key] = this.tickets[key];
}
}
session.tickets = tickets;
return session;
});
},
},
});
<div v-for="session in filteredSessions">
<div v-for="ticket in session.tickets">
{{ ticket.attr }}
</div>
</div>

ES5 only: return value when match is found after iterating over various values in an array

I am writing a function to return an id based on a few various things aligning. The code mostly works except that because there is no break; for a forEach. I believe I need to use a different filter or find option on the array.
function getDefaultId(prod) {
var defaultId;
prod.images.forEach( function(image) {
defaultId = image.isPrimary ? image.id : undefined;
});
return defaultId;
}
var prod.images = [
0: {
isPrimary: false,
id: 1234
},
1: {
isPrimary: true,
id: 1235
},
2: {
isPrimary: false,
id: 1236
}
]
Essentially I'm trying to return the corresponding id for isPrimary. The result should be 1236 but I'm getting undefined because the forEach is not breaking and thus is resetting the variable to undefined on the next iteration.
You could use Array#some and exit early.
function getDefaultId(prod) {
var defaultId;
prod.images.some(function (image) {
if (image.isPrimary) {
defaultId = image.id;
return true;
}
});
return defaultId;
}
var prod = { images: [{ isPrimary: false, id: 1234 }, { isPrimary: true, id: 1235 }, { isPrimary: false, id: 1236 } ]};
console.log(getDefaultId(prod));
var images = [
{
isPrimary: false,
id: 1234
},
{
isPrimary: true,
id: 1235
},
{
isPrimary: false,
id: 1236
}
]
let result = images.filter(img => img.isPrimary === true)
console.log(result)
You could use .filter() and to get an array of objects which have isPrimary as true, and then return the id of the first item found like so:
function getDefaultId(prod) {
var primaryImg = prod.images.filter(function(img) {
return img.isPrimary;
});
return primaryImg[0].id;
}
var prod = {};
prod.images = [{isPrimary: false, id: 1234 }, {isPrimary: true, id: 1235}, {isPrimary: false, id: 1236}];
console.log(getDefaultId(prod));
Give it a try using map.
var images = [
{
isPrimary: false,
id: 1234
},
{
isPrimary: true,
id: 1235
},
{
isPrimary: false,
id: 1236
}
];
function getDefaultId() {
var defaultId;
images.map(function (image) {
if (image.isPrimary) {
defaultId = image.id;
}
});
return defaultId;
}
console.log(getDefaultId());

Extending Vue component results in multiple GET calls

I have a Base Vue Component, which handles items. Now i've extended that component with a CompanyItem and a EducationItem. But when i load both the directives, it will call a GET method 4 times. Also: i have a click handler on 2 models (example: openUpdateOrCreateModal()) which is loaded in one of the directives. When i click, the other directive is triggered too. Anyone a idea?
Base
module.exports = {
props: ['user', 'update_url', 'store_url', 'delete_url', 'show_url', 'index_url', 'item_type'],
mounted() {
Bus.$emit('index');
},
data(){
return {
form: {},
items: [],
mainItem: {},
item: {},
}
},
created(){
},
methods: {
resetForm(){
this.form = new SparkForm({
general: {
title: null,
},
item: this.getItemProperties(),
address: {
address_line_1: null,
address_line_2: null,
city: null,
province: null,
zip_code: null
}
});
this.mainItem = null;
},
getItemProperties(){
return {};
},
showModal(){
$('#create-update-'+this.item_type+'-modal').modal('show');
},
hideModal(){
$('#create-update-'+this.item_type+'-modal').modal('hide');
},
/**
* Gets a list with specific items
*/
index(){
console.log('Call index');
axios.get(this.index_url)
.then(response =>
{
this.items = response.data.data;
});
},
}
};
Education
var base = require('./cv-item-base');
Vue.component('cv-educations-management', {
mixins: [base],
methods: {
getItemProperties(){
return {
start_at: null,
end_at: null,
description: null,
finished_education: null,
level: null,
}
}
}
});
Companies
var base = require('./cv-item-base');
Vue.component('cv-company-list', {
mixins: [base],
methods: {
getItemProperties(){
return {
start_at: null,
end_at: null,
position: null,
description: null,
phone_number: null,
branch: null,
referral: null,
}
}
}
});
HTML
<cv-company-management :user="user"
:update_url="'{{route('application.manage.companies.update')}}'"
:show_url="'{{route('application.manage.companies.show')}}'"
:delete_url="'{{route('application.manage.companies.destroy')}}'"
:store_url="'{{route('application.manage.companies.store')}}'"
:index_url="'{{route('application.manage.companies.index')}}'"
:item_type="'company'"
inline-template>
</cv-company-management>
<cv-education-management :user="user"
:update_url="'{{route('application.manage.educations.update')}}'"
:show_url="'{{route('application.manage.educations.show')}}'"
:delete_url="'{{route('application.manage.educations.destroy')}}'"
:store_url="'{{route('application.manage.educations.store')}}'"
:index_url="'{{route('application.manage.educations.index')}}'"
:item_type="'education'"
inline-template>
</cv-education-management>

How to apply where condition to backbone query

I'm building an app with Appcelerator.
I use Backbone to get data from database.
So I have build this code to get data from database:
var collection = Alloy.createCollection("SocialHistoryDAO");
collection.fetch();
Now I want to apply a where at this collection. So I use this code:
collection.where(id : 5);
Then this code works, but now I want to apply this filter:
"WHERE ID != 5";
It is possible to do this?
EDIT:
this is my SocialHistoryDAO model:
exports.definition = {
config: {
columns: {
"ID": "INTEGER PRIMARY KEY AUTOINCREMENT",
"IdOmnia": "INTEGER",
"DateStart": "text",
"DateEnd": "text",
"Quantity": "decimal",
"Code": "text",
"CodeSystem": "text",
"DisplayName": "text",
"DisplayNameTarget": "text",
"UnityMeasure": "text",
"StateID": "INTEGER"
},
adapter: {
type: "sql",
collection_name: "SocialHistoryDAO",
idAttribute: "ID"
}
},
extendModel: function(Model) {
_.extend(Model.prototype, {
// extended functions and properties go here
});
return Model;
},
extendCollection: function(Collection) {
_.extend(Collection.prototype, {
destroyAll : function(opt) {
var db = Ti.Database.open(this.config.adapter.db_name);
db.execute("DELETE FROM " + this.config.adapter.collection_name);
db.close();
this.models = [];
if (!opt || !opt.silent) { this.trigger("reset"); }
return this;
}
});
return Collection;
}
};
If you're using Backbone, then you're also using Underscore (or LoDash).
This can be accomplished using either:
var newArray = _.filter(collection.models, function(model) { return model.get('ID') != 5; });
or
var newArray = _.reject(collection.models, function(model) { return model.get('ID') == 5; });

Set selected on nested object knockout js

I have a complex object and I'm trying to set the
SelectedTransportation
property which I manually add in a mapping. The code properly populates the dropdownlist, but I can't figure out how to set SelectedTransportation properly. I've tried setting it during the mapping process and after mapping through a loop but all attempts have failed. Seems like this should be rather easy, but the solution eludes me.
var model = {"LoadCarriers":[
{
"Id":1,
"IsDispatched":false,
"IsPrimary":false,
"RCNotes":null,
"CarrierId":4,
"Carrier":{
"Id":4,
"Name":"West Chase",
"MCNumber":"EPZEPFEEGJAJ",
"DOTNumber":"AJSCEXFTFJ",
"InternetTruckStopCACCI":"DJOGRBQ",
"Phone":"0773283820",
"RemitToPhone":null,
"AlternatePhone":"4428290470",
"Fax":null,
"MainAddress":{
"ShortAddress":"Toledo, IN",
"Address1":"Lee St",
"Address2":"apt 131",
"City":"Toledo",
"State":"IN",
"PostalCode":"07950",
"Country":"US"
},
"RemitToAddress":{
"ShortAddress":"Fuquay Varina, MO",
"Address1":"Manchester Rd",
"Address2":"",
"City":"Fuquay Varina",
"State":"MO",
"PostalCode":"23343",
"Country":"US"
},
"EmailAddress":"jason.price14#gmail.com",
"Coverage":null,
"CanLoad":false,
"InsuranceNumber":"RIQERAIAJBMP",
"InsuranceExpirationDate":"\/Date(1442978115587)\/",
"AdditionalInsurance":null,
"ProNumber":"07643",
"URL":"http://www.west-chase.com",
"AccountId":1
},
"Dispatcher":"Bob McGill",
"DriverId":null,
"LoadDriver":{
"Id":1,
"Name":"Bobby Pittman",
"Phone":"8950121068",
"Mobile":null,
"MT":false,
"Tractor":"OQRNBP",
"Trailer":"QTZP",
"Location":"Lee St",
"TansportationSize":"958424896573544192",
"Pallets":null,
"IsDispatched":false,
"TransportationId":7,
"Transportation":{
"Name":"Flatbed or Van",
"Id":7
},
"TransportationList":[
{
"Name":"Flat",
"Id":1
},
{
"Name":"Van or Reefer",
"Id":2
},
{
"Name":"Rail",
"Id":3
},
{
"Name":"Auto",
"Id":4
},
{
"Name":"Double Drop",
"Id":5
},
{
"Name":"Flat with Tarps,",
"Id":6
},
{
"Name":"Flatbed or Van",
"Id":7
},
{
"Name":"Flatbed, Van or Reefer",
"Id":8
},
{
"Name":"Flatbed with Sides",
"Id":9
},
{
"Name":"Hopper Bottom",
"Id":10
},
{
"Name":"Hot Shot",
"Id":11
},
{
"Name":"Lowboy",
"Id":12
},
{
"Name":"Maxi",
"Id":13
},
{
"Name":"Power Only",
"Id":14
},
{
"Name":"Reefer w/ Pallet Exchange",
"Id":15
},
{
"Name":"Removable Gooseneck",
"Id":16
},
{
"Name":"Step Deck",
"Id":17
},
{
"Name":"Tanker",
"Id":18
},
{
"Name":"Curtain Van",
"Id":19
},
{
"Name":"Flatbed Hazardous",
"Id":20
},
{
"Name":"Reefer Hazardous",
"Id":21
},
{
"Name":"Van Hazardous",
"Id":22
},
{
"Name":"Vented Van",
"Id":23
},
{
"Name":"Van w/ Pallet Exchange",
"Id":24
},
{
"Name":"B-Train",
"Id":25
},
{
"Name":"Container",
"Id":26
},
{
"Name":"Double Flat",
"Id":27
},
{
"Name":"Flatbed or Stepdeck",
"Id":28
},
{
"Name":"Air",
"Id":29
},
{
"Name":"Ocean",
"Id":30
},
{
"Name":"Walking Floor",
"Id":31
},
{
"Name":"Landoll Flatbed",
"Id":32
},
{
"Name":"Conestoga",
"Id":33
},
{
"Name":"Load Out",
"Id":34
},
{
"Name":"Van Air-Ride",
"Id":35
},
{
"Name":"Container Hazardous",
"Id":36
}
],
"CarrierId":0,
"Carrier":null
},
"Carriers":null,
"LoadId":1
}
]};
var loadDriverModel = function (data) {
ko.mapping.fromJS(data, {}, this);
this.SelectedTransportation = ko.observable();
};
var loadDriverMapping = {
'LoadDriver': {
key: function (data) {
return data.Id;
},
create: function (options) {
return new loadDriverModel(options.data);
}
}
};
var carrierModel = function (data) {
ko.mapping.fromJS(data, loadDriverMapping, this);
};
var carrierMapping = {
'LoadCarriers': {
key: function (data) {
return data.Id;
},
create: function (options) {
return new carrierModel(options.data);
}
}
};
var model = ko.mapping.fromJS(model);
ko.applyBindings(model);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.js"></script>
<!-- ko foreach: LoadCarriers -->
<select class="form-control" data-bind="options:LoadDriver.TransportationList, optionsText:'Name', value:$data.LoadDriver.SelectedTransportation"></select>
<!-- /ko -->
#JasonlPrice I can't test right now, but I suggest you to not use this in loadDriverModel function.
Try create a variable and return that variable.
Something like this:
var loadDriverModel = function (data) {
var viewModel = ko.mapping.fromJS(data);
viewModel.SelectedTransportation = ko.observable();
return viewModel;
};
I ended up replacing this
var loadDriverModel = function (data) {
ko.mapping.fromJS(data, {}, this);
this.SelectedTransportation = ko.observable();}
with the following.
var loadDriverModel = function (data) {
var self = this;
ko.mapping.fromJS(data, {}, this);
this.SelectedTransportation = ko.computed(function () {
return ko.utils.arrayFirst(self.TransportationList(), function (item) { return item.Id() === self.TransportationId() });
}, self);
};
Now it works properly. Computed Observables were the solution.

Categories