Resetting backbone.js attributes hash - javascript

I've created a model in backbone:
var app={};
app.pilot_id = $("#user_id").val();
app.Pilot = Backbone.Model.extend({
url: POST_SUBMITTER.root + 'pilotdata/v1/pilot/',
sync: function(method, model, options) {
return Backbone.sync(method, this, $.extend(options, {
beforeSend: function (xhr) {
xhr.setRequestHeader ('X-WP-NONCE', POST_SUBMITTER.nonce);
}
}))
},
defaults : {
lastName: 'Doe',
firstName: 'John'
},
initialize : function() {
this.fetch({ data: ({id: app.pilot_id})});
}
});
app.pilot = new app.Pilot();
{ after the fetch lastName will be 'Smith' and firstName will be 'Sue'
and I create a view with backform.js
app.PilotForm = Backform.Form.extend({
el: $("#personalInformation"),
events: {
"submit": function(e) {
e.preventDefault();this.model.save( {patch: true})
.done(function(req, status, err) {
alert( status + ', ' + err);
console.log(status, err);
})
.fail(function(req, status, err) {
alert( status + ', ' + err);
});
return false;
}
},
fields: [
{name: "id", label: "Id", control: "uneditable-input"},
{name: "firstName", label: "First Name", control: "input"},
{name: "lastName", label: "Last Name", control: "input"},
{control: "button", label: "Save to server"}
],});
new app.PilotForm({model: app.pilot}).render();
This is going to be a multi-page form. And only a few fields will need to be updated each time. So I would like to update the server with "PATCH" However ALL of the fields that have been pre-filled from the fetch are flagged at changed. Therefore everything is sent in the PATCH request.
After creating the new app.PilotForm... I've added
app.pilot.attributes={};
This does work; now when I change a field only that field is sent in the PATCH request. However, the documentation suggests it is bad to mess directly with the attributes hash. Is there a better way to do this?

You can use model method such as changedAttributes, previousAttributes etc to find the info you want to send to the server and then use that patch option of model.save:
If instead, you'd only like the changed attributes to be sent to the server, call model.save(attrs, {patch: true}). You'll get an HTTP PATCH request to the server with just the passed-in attributes.
Where attrs is whatever you want to be the payload

Related

How to save, load and delete from database using a single ExtJS model?

Using ExtJS 6 one can have a store bind to the model and use the methods sync to save or load to load data.
I imagine that if a data is removed from store, upon calling sync the data will be removed from database too.
In my use case, I have different URLs and mandatory Ajax query fields for each action of create/update, load and delete data.
I have only seen examples showing load or save to storage, how can I declare the load, save and delete using Ajax in the same model?
Another doubt I have is that stores themselves can have a proxy, so they can perform those operations too, at least the load operation that I have seen in use. What's the difference between having these on the model or store? What's the best practice?
Example model from Sencha docs (is this only for read?):
Ext.define('MyApp.model.Base', {
extend: 'Ext.data.Model',
fields: [{
name: 'id',
type: 'int'
}],
schema: {
namespace: 'MyApp.model', // generate auto entityName
proxy: { // Ext.util.ObjectTemplate
type: 'ajax',
url: '{entityName}.json',
reader: {
type: 'json',
rootProperty: '{entityName:lowercase}'
}
}
}
});
Another example I found on https://examples.sencha.com/extjs/6.0.1/examples/classic/writer/writer.html using the proxy config, this seems more like what I would need as it specifies a URL for each operation:
var store = Ext.create('Ext.data.Store', {
model: 'Writer.Person',
autoLoad: true,
autoSync: true,
proxy: {
type: 'ajax',
api: {
read: 'app.php/users/view',
create: 'app.php/users/create',
update: 'app.php/users/update',
destroy: 'app.php/users/destroy'
},
reader: {
type: 'json',
successProperty: 'success',
root: 'data',
messageProperty: 'message'
},
writer: {
type: 'json',
writeAllFields: false,
root: 'data'
},
listeners: {
exception: function(proxy, response, operation){
Ext.MessageBox.show({
title: 'REMOTE EXCEPTION',
msg: operation.getError(),
icon: Ext.MessageBox.ERROR,
buttons: Ext.Msg.OK
});
}
}
},
listeners: {
write: function(proxy, operation){
if (operation.action == 'destroy') {
main.child('#form').setActiveRecord(null);
}
Ext.example.msg(operation.action, operation.getResultSet().message);
}
}
});
I believe I can have something like this in my case (this is just an example not tested!):
Ext.define('My.Person.Model', {
proxy: {
type: 'ajax',
api: {
read: 'http://myapiserver/getuser',
create: 'http://myapiserver/upsertuser',
update: 'http://myapiserver/upsertuser',
destroy: 'http://myapiserver/removeuser'
},
reader: {
type: 'json',
successProperty: 'success',
root: 'data',
messageProperty: 'message'
},
writer: {
type: 'json',
writeAllFields: false,
root: 'data'
},
// How can I have the parameters for each one?
extraParams : {
isuserUnderage : ' '
, query : '%'
}
}
});
I have no idea how to do this, specially specifying parameters for each type of Ajax request (read, create, update, destroy), I can have an upsert request that will send all fields, but the remove request will require only the ID, the get request can have optional fields for filtering, like filtering persons by name.
Example to be more clear of the problem.
Example data:
[
{
"id": "1",
"name": "Fred",
"age": 21,
"sex": "m"
},
{
"id": "2",
"name": "Susan",
"age": 12,
"sex": "f"
},
{
"id": "3",
"name": "Marcus",
"age": 22,
"sex": "m"
},
{
"id": "4",
"name": "Alex",
"age": 32,
"sex": "m"
}
]
Endpoints example:
Endpoints have parameters, these are mandatory, this means that calling an enpoint without a parameter will cause a server error, also passing a parameter that is not specified will cause a server error! If a parameter is not necessary one can pass a string with a single whitespace .
To read:
Endpoint: http://myapiserver/getuser?query={query}
Name is a filter by name, for example http://myapiserver/getuser?query=fred will bring users with name that has the string fred.
To write, we usually have an upsert, so it works for both insert and update:
Endpoint: http://myapiserver/upsertuser?id={id}&name={name}&age={age}&sex={sex}
So to update we can pass the ID: http://myapiserver/upsertuser?id=1&name=Frederick&age=21&sex=m and to insert we pass an empty string for ID: http://myapiserver/upsertuser?id= &name=Maurice&age=41&sex=m
To remove:
Endpoint: http://myapiserver/removeuser?id={id}
Example: http://myapiserver/removeuser?id=1, removes person with ID 1.
Because you say it's mandatory to use GETs with query params, I would encourage you to rethink your tech stack because the RESTful verbs really make it more clear what your action is, and you remove the actual action from your URL routes. However, I know sometimes this is totally out of our control, so I'll try my best here... I have to say, I've never experienced something like this, so I don't know if what I'm showing here is a best practice.
I can't show a true implementation because Sencha Fiddle is a simple sandbox, not meant for actual server-side implementations. I'm also assuming that you're using the classic toolkit, but if you need it in modern, it's a fairly easy port that you can do.
I prefer the proxy inside of the model for several reasons... if I need to use this model in several different stores throughout my app, then each store will inherit the same proxy. If I want to use the same model, but I don't want its proxy, I can simply override it when defining the store. Also, if the proxy doesn't exist on the model, then the framework assumes what your URL should be, which doesn't work when I want to use models individually.
I think I've come up with what you're asking for in this Fiddle. Really the core of what you want is in GETUser.js.
// We need to create our own proxy that will handle this for us
Ext.define('AjaxGet', {
extend: 'Ext.data.proxy.Ajax',
alias: 'proxy.ajaxGet',
// Per your requirement, we want to send individual requests
batchActions: false,
createOperation: function (action, config) {
// This means we're doing an action against one of our records
if (config && config.records) {
if (action === 'destroy') {
config.params = config.records[0].getDeleteParams();
} else if (action === 'create' || action === 'update') {
config.params = config.records[0].getUpsertParams();
}
}
return this.callParent(arguments);
}
});
// This is the desired, "GET" User model that uses GETs and query params for all actions
Ext.define('GETUser', {
extend: 'Ext.data.Model',
idProperty: 'Id',
fields: [{
name: 'Name',
type: 'string'
}, {
name: 'Id',
type: 'int'
}, {
name: 'Age',
type: 'int'
}, {
name: 'Sex',
type: 'string'
}],
proxy: {
type: 'ajaxGet',
api: {
read: 'Users',
create: 'upsertuser',
update: 'upsertuser',
destroy: 'removeuser'
},
actionMethods: {
create: 'GET',
update: 'GET',
destroy: 'GET'
}
},
getUpsertParams: function () {
const data = this.getData();
// Means this record hasn't been saved, so we're in the CREATE state
if (this.phantom) {
// We don't want to send the ID with what the framework sets as the ID
data.Id = undefined;
}
return data;
},
getDeleteParams: function () {
return {
Id: this.get('Id')
};
}
});
So what I ended up doing was creating a custom proxy that overrides the createOperation method to check which operation we're doing... based on that operation, we use the methods in the model to retrieve the params we want to send to the API. You need actionMethods in the proxy because otherwise, they default to POSTs.

Sails 1.0, How to call customToJSON from an Action2?

Well, I have a user model that needs to implement customToJSON and make the removal of the password for the object to be returned json.
When I put the "responseType" in "exits" as "json" everything happens fine, and the password is taken out of the response. However, the responseType: "json" will be deprecated according to the message in the terminal that sends the responseType empty, however the customToJSON is not called. Can anyone help me understand this?
this is the model code:
[...]
attributes: {
name: {
type: 'string',
required: true,
},
email: {
type: 'string',
required: true,
},
password: {
type: 'string',
minLength: 6,
required: true,
},
},
customToJSON: function() {
return _.omit(this, ['password']);
},
[...]
this is the action code:
module.exports = {
friedlyName: 'Users List',
description: 'User list -> all users',
exits: {
success: {
}
},
fn: async (inputs, exits) => {
var users = await User.find();
return exits.success(users);
}
}
this is the message if you put the "responseType: 'json'":
The json response type will be deprecated in an upcoming release. Please use `` (standard) instead (i.e. remove responseType from the success exit.)
I defined custom responses inside api/responses folder.
So, for example... for 200 OK response create api/responses/ok.js
and then inside action2 controller method add this to exits:
exits: {
success: {
description: 'Returns ok response from api/responses/ok.js',
responseType: 'ok'
}
}, ...
Example of my simple api/responses/ok.js
module.exports = function ok(data) {
return this.res.status(200).json(data);
};
You can create responses for each status/exit you need and later on it's easy to maintain exits... I have responses for: badRequest, serverError, forbidden, notFound and unauthorized

Meteor Quick Form doesnt submit

im doing the "Intermediate Meteor Tutorial #8 - Insert Permissions, Publishing & Meteor Toys" by LevelUpTuts and my problem is that i cant submit the form i checked the code 5 times but in my opinion everything is right im running meteor 1.4 here is my code
my Recipes.js file
Recipes = new Meteor.Collection('recipes');
Recipes.allow({
insert: function(userId, doc) {
return !!userId;
}
});
RecipeSchema = new SimpleSchema ({
name: {
type: String,
label: "Name"
},
desc: {
type: String,
label: "Description"
},
author: {
type: String,
label: "Author",
autoValue: function() {
return this.userID
},
autoform: {
type: "hidden"
},
},
createdAt: {
type: Date,
label: "CreatedAt",
autoValue: function() {
return new Date()
},
autoform: {
type: "hidden"
},
},
});
Recipes.attachSchema( RecipeSchema);
my recipes.js
Meteor.subscribe('recipes');
my NewRecipe.js
<template name="NewRecipe">
<div class="new-recipe-container">
{{> quickForm collection="Recipes" id="insertRecipeForm" type="insert" class="new-recipe-form"}}
</div>
</template>
and the publis.js file
Meteor.publish('recipes', function(){
return Recipes.find({author: this.userId});
});
Please help me i dont know what i am doing wrong
i don't have the answer for you (at least not yet), but i'm posting this as an answer so i can provide some formatted code.
you posted some code under NewRecipe.js, but i assume that view code is in NewRecipe.html. Try 2 things:
first, put this code in NewRecipe.js onCreated():
SimpleSchema.debug = true;
AutoForm.addHooks(null, {
onError: function(name, error, template) {
console.log(name + " error:", error);
}
});
that will enable some debugging for the quickform.
second, in the schema definition, comment out the Recipes.allow() block to see if that's what's blocking saving your data.
then report back on how that goes.

update parameters variable on change.search using bootgrid with structured-filter

I am using https://github.com/evoluteur/structured-filter and http://www.jquery-bootgrid.com/ to create an advanced search through ajax/php.
Initially the code works and returns the data from the php file, but when trying to use structured-filter to pass $_GET variables to the php file through the use of jquery-bootgrid I am struggling.
No matter what I try, the url it is posting to has no $_GET variables, I have tried $("#grid-data").bootgrid("reload"); but nothing changes.
It appears the params variable is just not updating.
Here is my jquery script in full:
<script type="text/javascript">
$(document).ready(function() {
$("#myFilter").structFilter({
fields: [{
type: "text",
id: "gamertag",
label: "Gamertag"
}, {
type: "text",
id: "name",
label: "Team Name"
}, {
type: "number",
id: "wagePerMatch",
label: "Wage Per Match"
}, {
type: "number",
id: "gamesRemaining",
label: "Contract Games Remanining"
}, {
type: "boolean",
id: "transferListed",
label: "Transfer Listed"
}
]
});
var params = "";
$("#myFilter").on("change.search", function(event) {
var params = $("#myFilter").structFilter("valUrl");
$("#grid-data").bootgrid("reload");
console.log(params); // works, returns params
});
$("#grid-data").bootgrid({
ajax: true,
url: function() {
return "/api/search.php?" + params; // params never updates?
}
});
});
</script>
Is there a way to update params in .bootgrid when it changes in $("#myFilter").on("change.search" as right now its only sending requests to /api/search.php? (missing the parameters)
Now i don't have to much reputation, i am unable to add comment on this,
Please check this below URL, hope this will help you
http://www.jquery-bootgrid.com/Documentation#events
if you are looking for append the rows in existing grid so you can use "append" as given in URL or if you want to update the whole table you can destory the table and re-create a "bootgrid" object with binding with the respective DOM id's

Merge an Item Fulfillment with an advanced template and email it Netsuite 2.0

So without the merge function below, this code sends an email on save, but I cannot for the life of me get email merge to work in Netsuite 2.0, so how do I merge an advanced pdf template with an item fulfillment and email it?
/**
*#NApiVersion 2.x
*#NScriptType UserEventScript
*/
define(['N/email','N/render', 'N/record', 'N/file'],
function(email, record, file,render) {
function afterSubmit(context) {
function templatemerge() {
var myMergeResult = render.mergeEmail({
templateId: 121,
entity: {
type: 'employee',
id: 18040
},
recipient: {
type: 'employee',
id: 18040
},
supportCaseId: 'NULL',
transactionId: 1176527,
customRecord: 'NULL'
});
}
templatemerge();
function sendEmailWithAttachement() {
var newId = context.newRecord;
var emailbody = 'attachment';
var senderId = 18040;
var recipientEmail = 'email#email.com';
email.send({
author: senderId,
recipients: recipientEmail,
subject: 'Item Fulfillments',
body: emailbody
});
}
sendEmailWithAttachement();
}
return {
afterSubmit: afterSubmit
};
});
Try rearranging the first function signature to function(email, render, record, file)
They are probably in the wrong order.

Categories