Set values to the folded defaults in Backbone.Model - javascript

I have an object inside defaults like this:
app.MultiwidgetModel = Backbone.Model.extend({
defaults : {
....
operatorData : {
helloBlock : null,
greeting : null,
avatarBlock : null,
avatarImg : null
},
....
},
initialize: function(){
....
}
});
How can I set values to the operatorData inner properties (helloBlock, greeting) etc in the initialize function? If it is possible, what syntax should I use?

If you just want to set values to the current model in initialize and trigger the approriate change events, this should work:
app.MultiwidgetModel = Backbone.Model.extend({
defaults : {
....
operatorData : {
helloBlock : null,
greeting : null,
avatarBlock : null,
avatarImg : null
},
....
},
initialize: function(){
var opData = this.get('operatorData');
opData.helloBlock = 'foo';
opData.greeting = 'bar';
...
this.set({operatorData: opData}); // Without this, the data will change but you won't have a change:operatorData event triggered
}
});
If you want to edit the default values you should be able to use
app.MultiwidgetModel.prototype.defaults.operatorData = {
helloBlock : 'foo',
greeting : 'bar'
}
Is that what you want?

Related

Accessing a variable in vuejs or javascript

I have this javascript variable, I'm using vuejs.
when I try to access an array field to validate a form, the chrome dev tools returns an error.
var checkItems = {contact_email: "", contact_name: "", contact_phone: "", message: "", subject_id: null, …}
I try to access this way:
if(checkItems.contact_email)
alert("email required");
This is the error:
Property or method "contact_email" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option
If the form fields are empty, I want to detect individually which one is empty and send a custom error for each one, for example:
Name field is empty
The email field is empty
This is my vuejs code:
var locale = '{{ $lang }}'; //'es-ES',
var V_Alerts = new Vue({
el : '#v-alerts',
data : {
types : ['danger', 'warning', 'success', 'info'],
alerts : [
]
},
methods : {
add : function(type, content, opts)
{
this.alerts.push({
type : type,
content : content,
opts : opts
});
},
addSuccess : function(content, opts){
this.add('success',content, opts)
}
}
});
var new_ticket = new Vue({
el : '#create_ticket',
data : {
uploading : false,
submitting : false,
subject_id : null,
message : '',
errors: [],
},
methods : {
validation: function (params)
{
return {
contact_email : IsEmail(params.contact_email),
contact_name : !!params.contact_name.trim(),
message : !!params.message.trim(),
subject_id : params.subject_id && !!params.subject_id.trim(),
captcha : params.captcha !== 0
}
},
isValid : function(params)
{
var validation = this.validation(params);
return Object.keys(validation).every(function (key) {
return validation[key];
});
},
restart : function()
{
this.uploading = false;
this.submitting = false;
this.subject_id = null;
this.$refs.subjects.restart();
this.$refs.uploads.restart();
$('#message').text('');
$('#order_number').val('');
$('#contact_email').val('');
$('#contact_name').val('');
$('#contact_phone').val('');
$('#message').val('');
grecaptcha.reset();
},
onSubjectSelect : function(subject_id){
this.subject_id = subject_id;
},
_onSubjectsLoaded : function(subjects){
emitOnWidgetContentChanged();
},
createTicket : function(e)
{
var params = {
contact_email : $('#contact_email').val(),
contact_name : $('#contact_name').val(),
contact_phone : $('#contact_phone').val(),
message : $('#message').val(),
subject_id : this.subject_id,
message_files : this.$refs.uploads.completed_ids.join(','),
captcha : grecaptcha.getResponse()
};
#if (Input::has('public_token'))
params.public_token = '{{ Input::get('public_token') }}';
#endif
if ($('#order_number').val() != '')
params.contact_orders = $('#order_number').val();
if (!this.isValid(params))
{
var checkItems = params;
if(checkItems.contact_email)
alert("email");
alert('{{ addslashes(trans('common.empty_or_error_input')) }}');
return;
}
this.submitting = true;
// only ie11 need this manuall
params._token = '{!! csrf_token() !!}';
AjaxServices.post('createTicket', params, function(error, result)
{
this.submitting = false;
if (error)
{
alert('{{ addslashes(trans('accounts/tickets.error_creating_ticket')) }}');
grecaptcha.reset();
}
else
{
alert('#'+ result.ticket_id +' - {{ addslashes(trans('accounts/tickets.new_ticket_created_ok')) }} :)');
V_Alerts.addSuccess('#'+ result.ticket_id +' - {{ addslashes(trans('accounts/tickets.new_ticket_created_ok')) }}');
this.restart();
emitOnWidgetContentChanged();
}
}.bind(this));
},
onUploadComplete : function(ids){
this.uploading = false;
emitOnWidgetContentChanged();
},
onUploadStarted : function(){
this.uploading = true;
setTimeout(emitOnWidgetContentChanged,1);
},
onItemDeleted : function(){
},
onFilesSelected : function(){
}
}
});
function IsEmail(email) {
var regex = /^([a-zA-Z0-9_.+-])+\#(([a-zA-Z0-9-])+\.)+([a-zA-Z0-9]{2,4})+$/;
return regex.test(email);
}
$(document).ready(function(){
//new_ticket.restart();
});
You are not utilizing Vue properly. The error you are receiving stems from not defining your properties in the data object. You cant just return them as you are in the validation method because Vue is looking for a data object called contact_email, or a method called contact_email() or even a computed property called contact_email.
data : {
// define your properties here
contact_email: '';
},
methods: {
yourMethod: function(){
//modify your properties here
this.contact_email: IsEmail(params.contact_email)
}
}

Detail page of split app without model

In my split app the detail view does not bind any model.
In the component.js I instantiate a named model like this:
// creation and setup of the oData model
var oConfig = {
metadataUrlParams: {},
json: true,
defaultBindingMode : "TwoWay",
defaultCountMode : "Inline",
useBatch : false
}
// ### tab-employee ###
var oModelEmpl = new sap.ui.model.odata.v2.ODataModel("/sap/opu/odata/sap/EMP_SRV"), oConfig);
oModelEmpl.attachMetadataFailed(function() {
this.getEventBus().publish("Component", "MetadataFailedEMPL");
}, this);
this.setModel(oModelEmpl, "EMPL");
The method onSelect in der master-view controller is fired by clicking on an listitem.
onSelect: function(oEvent) {
this.showDetail(oEvent.getParameter("listItem") || oEvent.getSource());
}
This will call the method showDetail
showDetail: function(oItem) {
var bReplace = jQuery.device.is.phone ? false : true;
this.getRouter().navTo("detail", {
from: "master",
entity: oItem.getBindingContext('EMPL').getPath().substr(1),
}, bReplace);
},
In the controller of the detail-view I've these two methods for updating the binding. onRouteMatched calls bindView, where I get the error-message TypeError: oView.getModel(...) is undefined.
onRouteMatched: function(oEvent) {
var oParameters = oEvent.getParameters();
jQuery.when(this.oInitialLoadFinishedDeferred).then(jQuery.proxy(function() {
var oView = this.getView();
if (oParameters.name !== "detail") {
return;
}
var sEntityPath = "/" + oParameters.arguments.entity;
this.bindView(sEntityPath);
}, this));
},
bindView: function(sEntityPath) {
var oView = this.getView();
oView.bindElement(sEntityPath);
//Check if the data is already on the client
if (!oView.getModel().getData(sEntityPath)) {
// Check that the entity specified was found.
oView.getElementBinding().attachEventOnce("dataReceived", jQuery.proxy(function() {
var oData = oView.getModel().getData(sEntityPath);
if (!oData) {
this.showEmptyView();
this.fireDetailNotFound();
} else {
this.fireDetailChanged(sEntityPath);
}
}, this));
} else {
this.fireDetailChanged(sEntityPath);
}
},
I've tried to implement this split app relative to the template generated by WebIDE. Any idea what is missing?
As you wrote yourself, you are creating a "named Model" with the name "EMPL".
In the Controller you have to use the same name to get the Model:
this.getView().getModel("EMPL");
Likewise when calling bindElement() you have to give the model name:
// Assuming sEntityPath = "/items/0"
this.getView().bindElement("EMPL>" + sEntityPath);

Meteor, display/sort value by boolean

I'm working on a table in Meteor template, where the is a boolean field "emergency"
I would like to display in the table the cells where there is the "emergency" flag FIRST, and then the others ...
How can I do that please ?
here is the find, I tried to sort(), find and sort inside but It doesn't work .. :/
Template.actionsList.helpers({
actions: function() {
return Actions.find();
}
});
Thanks in advance :)
I get the error: Exception in template helper: TypeError: Cannot read property 'hasOwnProperty' of null
My code is:
Session.set('emergency', false);
Template.actionForm.onRendered(function () {
var $elem = this.$('.emergency');
$elem.checkbox('set ' + (Session.get('emergency') ? 'checked' : 'unchecked'));
$elem.checkbox({
onChange: function () {
Session.set('emergency', !Session.get('emergency'));
}
});
});
Template.actionForm.events({
'submit .new-action': function(event) {
event.preventDefault();
var emergency = Session.get('emergency');
...
Actions.insert({
emergency: emergency
....
Thanks for the help
Use underscore's sortBy() method to sort on objects checking if the 'emergency' field exists via the hasOwnProperty() native method:
Template.actionsList.helpers({
actions: function() {
var actions = Actions.find().fetch();
return _.sortBy(actions, function (a) { return !a.hasOwnProperty('emergency'); });
}
});
Check the demo below.
var actions = [
{
"_id" : "ukn9MLo3hRYEpCCty",
"field" : "foo"
},
{
"_id" : "ukn9MLo3hRYEpCCty",
"field" : "bar",
"emergency": true
},
{
"_id" : "WMHWxeymY4ATWLXjz",
"field" : "abc",
"emergency": false
},
{
"_id" : "5SXRXraariyhRQACe",
"field" : "xyz"
}
];
var result = _.sortBy(actions, function (a) { return !a.hasOwnProperty('emergency'); });
pre.innerHTML = JSON.stringify(result, undefined, 4);
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore-min.js"></script>
<pre id="pre"></pre>

Composite properties in constructor

I want to build an array of objects which look like this:
var someObject = {
id,
groupA {
propertyA: 0,
propertyB: 0,
},
groupB {
propertyA: 0,
propertyB: 0
totals {}
}
And add the following composite property:
Object.defineProperty(someObject.groupA, "propertyC",
{
get: function() {
return someObject.groupA.propertyA + someObject.groupA.propertyB;
}
});
And use the same method to add the properties:
groupB.propertyC -> groupB.propertyA + groupB.propertyB
totals.propertyA -> groupA.propertyA + groupB.propertyA
totals.propertyB -> groupA.propertyB + groupB.propertyB
totals.propertyC -> groupA.propertyC + groupB.propertyC
I got all this working by putting all this code in a function so it added someObject to an array.
But then I got to thinking that the read-only composite properties shouldn't need to be created for each object and could probably be in a prototype.
Does this make sense? And is it possible, and if so: how?
It can be done. You just need to make sure that groupA and groupB inherit from an object which has the composite property.
var proto = {};
Object.defineProperty(proto, 'propertyC', {
get : function() { return this.propertyA + this.propertyB; }
});
var someObj = {
id : '1',
groupA : Object.create(proto, {
propertyA : { value : 1 }, propertyB : { value : 2 }
}),
groupB : Object.create(proto, {
propertyA : { value : 3 }, propertyB : { value : 4 }
}),
totals : Object.create(proto, {
propertyA : { get : function() { return someObj.groupA.propertyA + someObj.groupB.propertyA; } },
propertyB : { get : function() { return someObj.groupA.propertyB + someObj.groupB.propertyB; } }
})
}
// Usage:
console.log(someObj.groupA.propertyC); // 3
console.log(someObj.groupB.propertyC); // 7
console.log(someObj.totals.propertyC); // 10
I don't know if understood well your question; but in general when you have members that you want to share across all the instances of a particular type then you should put them into the prototype of the constructor.
In your example, you're using object literal, which doesn't make it easy to do so, unless you extend the prototype of the Object constructor, which I would not recommend.
How about doing something like this:
var SomeType = function(){
this.id = 0;
this.groupA = {
propertyA: 0,
propertyB: 0
};
this.groupA = {
propertyA: 0,
propertyB: 0
};
this.total = {};
}
SomeType.prototype = {
constructor: SomeType
}
Object.defineProperty(SomeType.prototype, 'propertyC', {
get: function(){ return this.groupA.propertyA + this.groupA.propertyB }
});

javascript calling init function after setup

I am trying to create a js object, I want either the user passes in some json data or the objects properties are set by default as shown below. After that is all set, I finally want to call an init function that runs and does the work. Thanks for any help. I am not trying to create a jQuery plugin.
var PictureDialog = function (settings) {
settings = {
allowShortKey: true,
prevID: null,
prevCounterNumber: null,
startValue: 0,
nextValue: 1,
init: function() {
//Do work
//Show dialog
}
},settings;
}
Would the call look something like this
PictureDialog({prevID:1}).init();
Not sure why you would need an init function at all. This is how I would do it:
(function () {
var defaultSettings = {
allowShortKey: true,
prevID: null,
prevCounterNumber: null,
startValue: 0,
nextValue: 1
};
PictureDialog = function (settings) {
settings = settings || defaultSettings;
//Do work
//Show dialog
};
})();
The outer function is just to make sure that defaultSettings doesn't pollute the global scope.
If I understand correctly you want to set some default values, with the help of jQuery you can use $.extend like this:
function Foo( settings ) {
var _defaults = { a: 'a', b: 'b' };
settings = $.extend( settings, _defaults );
}
With pure JavaScript you'd have to do something like this:
function Foo( settings ) {
var _defaults = { a: 'a', b: 'b' };
settings.a = settings.a || _defaults.a;
settings.b = settings.b || _defaults.b;
}
As for the init method, you can just add it to the prototype and execute it in the constructor so you don't even have to call it when you create a new instance:
function Foo( settings ) {
var _defaults = { a: 'a', b: 'b' };
...
this.init();
}
Foo.prototype = {
init: function() {
console.log('initialized!');
}
}
The quick and simple way would be this:
var PictureDialog = function (settings)
{
settings = {
allowShortKey: true,
prevID: null,
prevCounterNumber: null,
startValue: 0,
nextValue: 1,
init: function()
{
//Do work
//Show dialog
return this;//<--return object, too
}
};
return settings;//return the object
};
foo = PictureDialog().init();//the init will be called on the return value of PictureDialog
I don't, however, get why the PictureDialog function expects a settings argument. Either pass nothing to the function at all, or alter the passed value:
var PictureDialog = (function()
{
var defaults = {
allowShortKey: true,
prevID: null,
prevCounterNumber: null,
startValue: 0,
nextValue: 1,
init: function()
{
//Do work
//Show dialog
return this;//<--Very important
};
return function (settings)
{
settings = settings instanceof Object ? settings : {};
for (var n in defaults)
{
if (defaults.hasOwnProperty(n))
{//set all properties that are missing from argument-object
settings[n] = settings[n] || defaults[n];
}
}
return settings;
};
}());
foo = PictureDialog({allowShortKey: false}).init();//will return full settings object

Categories