I am attempting to stop a record from being created based on a search result. I can't seem to return any data through my SuiteScript search though, even though I know for a fact the data exists.
I created a Custom Saved Search with the exact filter being used below and return the results I am looking for.
Does anything stand out on why I may not be retrieving any results?
NOTE: The sfdcAccountId Variable does have a value, so I am searching on a valid value.
// 2.0
define(["N/error", "N/log", "N/search"], function (err, log, search) {
/**
* User Event 2.0 example showing usage of the Submit events
*
* #NApiVersion 2.x
* #NModuleScope SameAccount
* #NScriptType UserEventScript
* #appliedtorecord customer
*/
var exports = {};
function beforeSubmit(scriptContext) {
log.debug({
"title": "Before Submit",
"details": "action=" + scriptContext.type
});
if (doesCustomerExist(scriptContext)) {
throw err.create({
"name": "DUPLICATE_SFDC_ACCOUNT_ID",
"message": "Customer Already Contains SFDC Account Id",
"notifyOff": true
});
}
}
function doesCustomerExist(scriptContext) {
var sfdcAccountId = scriptContext.newRecord.getValue('custentitysfdc_account_id');
log.debug({
"title": "Before Submit",
"details": "sfdcAccountId=" + sfdcAccountId
});
if(sfdcAccountId == null || sfdcAccountId == '') return false;
var searchResult = search.create({
type: search.Type.CUSTOMER,
filters: ['custentitysfdc_account_id', search.Operator.IS, sfdcAccountId]
}).run();
return (searchResult != null && searchResult.length > 0);
}
exports.beforeSubmit = beforeSubmit;
return exports;
});
When you call .run() on a search, it returns a search.ResultSet object. If you call getRange() on that object, you'll get the array of results that you're looking for. Here's an updated version of your search that returns search.Result[] on which you can check the length or iterate through as necessary.
var searchResult = search.create({
type: search.Type.CUSTOMER,
filters: ['custentitysfdc_account_id', search.Operator.IS, sfdcAccountId]
}).run().getRange({start: 0, end: 1000});
Related
I are have a problem into my code. After many attempts in search for solutions I decided to get help from the stackoverflow community
I have created a Javascript Class for get registered members list. This members register is localized in to a Json file which system have access.
I'm trying to use an array data filter through forEach. But the method named: "Of(ChurchName)" don't read any foreach method into it. When I using into Of(), returns undefined.
Initially I used 'return' response in the method "createMemberList()", responsible to create the full array. This method it's working normally. But, using 'return' in a variable with ForEach method not work. Then, because this aparent error, I has used the 'this' operator instead of 'return'. But even so, as can you see in code, i can't use the forEach method at "createMemberList()".
Does anyone has any idea?
Details:
I aredy used that site tips:
https://www.techiedelight.com/copy-elements-array-into-another-array-javascript/
const $INIT = {
GetMembers: class{
#listaOrdenadaItens;
#listaMembros;
#MemberListOfChurch;
membersList;
#linkGFile="LinkToJsonFileHere";
/*Returns:
{
"range": "Membros!B5:AB234",
"majorDimension": "ROWS",
"values": [
[ "",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
""]
]
}
*/
constructor(ListFromGD){
if(typeof ListFromGD!=="undefined"&&ListFromGD!==null){
this.#linkGFile=ListFromGD;
}
this.#createMemberList();
}
/*Members List*/
Of(ChurchName){
/**Filters member data according congregation
* Usage: new $INIT.GetMembers().Of("ChurchName")
*/
this.#MemberListOfChurch=[];;
this.ChurchName=ChurchName;
this.membersList.forEach((item, count) => {
console.log("Why this code don't appears in console?");
if (/^[a-zA-Z_À-Úà-ú\s]{2,50}$/.test(ChurchName)==true && ChurchName.toLocaleLowerCase() == item.congregacao.toLocaleLowerCase()) {
this.#MemberListOfChurch[count] = item;
}else{
console.log("Trys to check anyone error");
}
});
return this.#MemberListOfChurch;
}
#getListaOrdenada (){
return [
/**Personal Informations */
"Nome Completo",
"Sexo",
"CPF",
"Data de Nascimento",
"RG",
"Orgão Emissor",
"UF_RG",
"Data de Expedição",
"Estado Civil",
"CONJUGE",
"Naturalidade",
"UF_NAT",
"NOME_PAI",
"NOME_MAE",
/**Schooling and ecclesiastical data */
"GRAU_INSTRUCAO",
"PROFISSAO",
"FUNCAO_ECLESIASTICA",
"LOCAL",
"UF_BATISMO",
/**Address informations */
"Endereco",
"cep",
"bairro",
"cidade",
"uf",
"congregacao",
"contact_number",
"whatsapp_number"
]
}
#createMemberList(){
var listaOrdenada = this.#getListaOrdenada();
/**Create an array */
var NewListMember = [];
var DadosMembros={};
/**
* Gets registered members list at system!
*/
this.#getJSON(this.#linkGFile).then(response=>{
response.values.forEach((item, i)=>{
/**Examina membro por membro aqui */
if(item[0]===undefined)return;
/**Creates a name for array of values: Ex: {"Complete Name" : "Leonardo Lima de Sousa"} */
listaOrdenada.forEach((ItemName,N)=>{
if(ItemName===undefined) return;
DadosMembros[ItemName]=item[N];
});
NewListMember[i] = DadosMembros;
DadosMembros={};
});
})
this.membersList=NewListMember;
}
#getJSON=async t=>{const r=await fetch(t);if(!r.ok)throw new Error(r.statusText);return r.json()};
}
}
If I run this code of this function directly in the Chrome Console, it's works. But in this Class Method, returns undefined
const newArr = [...arr1, ...arr2] will copy all the elements from arr1 and arr2 to newArr. You don't need to use foreach.
TEMPORARY SOLUTION
A temporary solution for this problem is copy CreateMemberList() content to Of() Method. Thereafter, It's necessary create a new Array named NewListMember[] and apply congregations data via objects to it where congregation name is equal ChurchName param
The Of() Method will be staying this:
Of(ChurchName){
/**Filters member data according congregation
* Usage: new $INIT.GetMembers().Of("ChurchName")
*/
var
listaOrdenada = this.#getListaOrdenada(),
NewListMember = [],
newArray = [],
DadosMembros = {};
/**
* Gets all registered members data by Json array.
*/
this.#getJSON(this.#linkGFile).then(response=>{
//Creates a counter variable
var newI=0;
response.values.forEach((item, i)=>{
/**examines member by member here */
if(item[0]===undefined)return;
/**Creates a property name for this array value: }
*Ex: {"Nome completo" : "Leonardo Lima de Sousa"}
* "Complete Name"
*/
listaOrdenada.forEach((ItemName,N)=>{
if(ItemName===undefined) return;
DadosMembros[ItemName]=item[N];
});
//Gets current congregation name and set all letters to lowerCase()
var ThisCongregation = DadosMembros.congregacao;ThisCongregation=ThisCongregation.toLowerCase();
//Gets congregation name in to param: ChurchName and set all letters to lowerCase()
var CongregationIndicate = ChurchName.toLowerCase();
//Gets Congregation where Congregation name is equal Param ChurchName
////Then, creates a new size for array NewListMember with newI counter
if(ThisCongregation!==undefined&&ThisCongregation!==CongregationIndicate)return;
NewListMember[newI] = DadosMembros;
++newI;
DadosMembros={};
});
});
return NewListMember
}
DEFINITIVE SOLUTION
where were problem?
What's solution?
The #createMemberList() generate an array with more than 220 rows. Then, it's necessary wait a while for Of() method to process everything.
For it, it's must to use setTimeout() function in the method, like this:
setTimeout(()=>{
console.log(JSON.stringify(this.membersList))
},3000)
The code will to stay like this:
const $INIT = {
GetMembers: class{
#listaOrdenadaItens;
#listaMembros;
#MemberListOfChurch;
membersList;
#linkGFile="https://cdn.jsdelivr.net/gh/OficialLeonardoLima/cdn#main/json_test.json";
constructor(ListFromGD){
if(typeof ListFromGD!=="undefined"&&ListFromGD!==null){
this.#linkGFile=ListFromGD;
}
this.#createMemberList();
setTimeout(()=>{
console.log(JSON.stringify(this.membersList))
},3000)
document.querySelector("#console").text=JSON.stringify(this.membersList)
}
/*Members List*/
Of(ChurchName){
/**Filters member data according congregation
* Usage: new $INIT.GetMembers().Of("ChurchName")
*/
this.#MemberListOfChurch=[];;
this.ChurchName=ChurchName;
setTimeout(()=>{
this.membersList.forEach((item, count) => {
console.log("Why this code don't appears in console?");
if (/^[a-zA-Z_À-Úà-ú\s]{2,50}$/.test(ChurchName)==true && ChurchName.toLocaleLowerCase() == item.congregacao.toLocaleLowerCase()) {
this.#MemberListOfChurch[count] = item;
}else{
console.log("Trys to check anyone error");
}
});
},3000);
return this.#MemberListOfChurch;
}
#getListaOrdenada (){
return [
/**Personal Informations */
"Nome Completo",
"Sexo",
"CPF",
"Data de Nascimento",
"RG",
"Orgão Emissor",
"UF_RG",
"Data de Expedição",
"Estado Civil",
"CONJUGE",
"Naturalidade",
"UF_NAT",
"NOME_PAI",
"NOME_MAE",
/**Schooling and ecclesiastical data */
"GRAU_INSTRUCAO",
"PROFISSAO",
"FUNCAO_ECLESIASTICA",
"LOCAL",
"UF_BATISMO",
/**Address informations */
"Endereco",
"cep",
"bairro",
"cidade",
"uf",
"congregacao",
"contact_number",
"whatsapp_number"
]
}
#createMemberList(){
var listaOrdenada = this.#getListaOrdenada();
/**Create an array */
var NewListMember = [];
var DadosMembros={};
/**
* Gets registered members list at system!
*/
this.#getJSON(this.#linkGFile).then(response=>{
response.values.forEach((item, i)=>{
/**Examina membro por membro aqui */
if(item[0]===undefined)return;
/**Creates a name for array of values: Ex: {"Complete Name" : "Leonardo Lima de Sousa"} */
listaOrdenada.forEach((ItemName,N)=>{
if(ItemName===undefined) return;
DadosMembros[ItemName]=item[N];
});
NewListMember[i] = DadosMembros;
DadosMembros={};
});
})
this.membersList=NewListMember;
}
#getJSON=async t=>{const r=await fetch(t);if(!r.ok)throw new Error(r.statusText);return r.json()};
}
}
I am writing a script to take a value from one field and place it into a list field in NetSuite. I believe the issue is because upon saving the record a value is trying to be set in a list that does not contain that value.
I want this to fail silently when set within the context of my script, how can I prevent the error message from showing up and allow the record to be created but without that field being populated?
Scenario - Value is placed into this field, the script tries to map that value to a list value (IT DOES NOT EXIST), the record should still save, but without that data being set - NO ERRORS.
/**
* #NApiVersion 2.x
* #NScriptType UserEventScript
* #NModuleScope SameAccount
*/
define(['N/record', 'N/log'],
/**
* #param {record} record
*/
function(record) {
function customer_beforeLoad(scriptContext) {
}
function customer_beforeSubmit(scriptContext) {
//Segment
setNonIntegrationFieldValue(scriptContext, 'custentity_cus_segmentintegration', 'custentity_cus_segment');
//Currency
setNonIntegrationFieldValue(scriptContext, 'custentity_cus_primarycurrencyintegratio', 'currency');
//Billing Cycle
setNonIntegrationFieldValue(scriptContext, 'custentity_cus_billingcycleintegration', 'custentity_cus_billingcycle');
//Type
setNonIntegrationFieldValue(scriptContext, 'custentity_cus_typeintegration', 'custentity_cus_type');
//Industry
setNonIntegrationFieldValue(scriptContext, 'custentity_cus_industryintegration', 'custentity_esc_industry');
//Sales Rep
setNonIntegrationFieldValue(scriptContext, 'custentity_cus_salesrepintegration', 'salesrep');
}
function customer_afterSubmit(scriptContext) {
}
function setNonIntegrationFieldValue(scriptContext, integrationFieldName, actualFieldName){
try {
var integrationFieldValue = scriptContext.newRecord.getValue(integrationFieldName);
if(integrationFieldValue == '' || integrationFieldValue == null){
scriptContext.newRecord.setValue({
fieldId: actualFieldName,
value: ''
});
} else {
scriptContext.newRecord.setText({
fieldId: actualFieldName,
text: integrationFieldValue
});
}
} catch(e){
log.error({
title: "setNonIntegrationFieldValue() has encountered an error.",
details: e.message
});
//nlapiLogExecution('ERROR','setNonIntegrationFieldValue() has encountered an error.', errText(e));
}
}
return {
//beforeLoad: customer_beforeLoad,
beforeSubmit: customer_beforeSubmit,
//afterSubmit: customer_afterSubmit
};
});
I think the solution should not be preventing a message from showing up, instead, it should be preventing setting of the value when it's not a valid value. You can try firstly get the array of all valid options in that list, secondly check if the value you want to use is contained in the array, if yes then set the value.
To be specific:
var actualField = scriptContext.form.getField(actualFieldName);
var options = actualField.getSelectOptions();
var integrationFieldValue = scriptContext.newRecord.getValue(integrationFieldName);
if (options.indexOf(integrationFieldValue) > -1) {
scriptContext.newRecord.setText({
fieldId: actualFieldName,
text: integrationFieldValue
});
}
For more details for the function getSelectOptions, please refer to Netsuite Help center (search Field.getSelectOptions)
Just wrap ANY AND ALL netsuite logic with a try catch. We have over 614,00 LOC in netsuite and this works 100%:
try {
// your code here
} catch (e) {
// this ternary operator will catch all the ns errors. you can fail silently here
var error = e.details || e.message || e.toString();
throw error;
}
I am writing a service in nodejs. Please read below for the approach i am doing to solve this problem.
First I call a rest endpoint(say /offers) to fetch data . say it cloudSenseData
Final Response I need to massage/manipulate the data to give back the needed response as output.
During massaging the data(from above call) I have to check if there is a relatedProduct info present.
if present I need to call another rest endpoint(say /offers/:id/products)
the :id is catalogueitemid obtained in previous call(cloudSenseData) to get more relatedProduct info details which i can include in the final massaged output.
So lets say in cloudSenseData I have 10 catalogueItems.
These are the steps i am doing during massaging the data:
Using async.map on cloudSenseData and mapping it to the needed response format.(I used it to make things parallel done)and have a callback function doing the need
In the callback apart while making the response as needed I am checking if it has relatedProduct info
if it doesnt have no issue
else i am calling downstream endpoint to get more relatedProductInfo using catologueItemId.(here i am using deasync )
This is taking more time than needed.
Can anyone please suggest any alternatives to approach this?
Update with Code : common-nodejs is a library we have written that wraps many functionalities like calling the rest endpoints using restify, reading the app configuration and many such. The below code is in typescript .
Hope this helps.
import {log,serviceInfo,HttpMethod} from "common-nodejs";
import { CloudsenseBaasJsonAction } from './cloudsense-baas-connector';
import {Constants} from "./Constants";
let request = require('request');
let deasync = require('deasync');
let moment = require("moment");
let async= require("async");
let PropertiesReader = require("properties-reader");
let endpointsConfigFile = require("../../config/endpoints.json");
//load the properties file to map the cloudsense attributes with required keys.
let parseConfig=new PropertiesReader("config/fields_config.properties");
// helper method in adding more details in response by reading the properties file
export let parsePropertiesFile = function(attribute,microserviceResponse,key,value){
let cloudSenseKey = attribute[key];
let microServiceKey = parseConfig.get(cloudSenseKey);
//console.log("********cloudSenseKey***************",cloudSenseKey,"************ microServiceKey***" ,microServiceKey);
if( microServiceKey!= undefined && microServiceKey!=null){
// console.log("********microServiceKey***************",microServiceKey ,attribute[value]);
microserviceResponse[microServiceKey] = attribute[value];
}
};
// this method does the fetching the detailed info if relatedProducts are there
export let requestRelatedProductsInfo = function(offerId):any{
// console.log("****************Above to Parse*******");
let body={};
let cloudsenseBaasJsonAction = new CloudsenseBaasJsonAction(HttpMethod.GET, body, '');
let sendRequestForRelatedProducts = deasync(function(callback){
request({
proxy: serviceInfo.extras.internetProxy,
url: serviceInfo.extras.serviceCloudsense.apiEndpoint+"/services/current/offer/"+offerId+"/products",
method: endpointsConfigFile.cloudsense_baas.offers.method,
headers: cloudsenseBaasJsonAction.modifyHeadersWithParams({
"csTime": Date.now(),
"method": HttpMethod[endpointsConfigFile.cloudsense_baas.offers.method],
"path": "/services/current/offer/"+offerId+"/products",
"clientKey": serviceInfo.extras.serviceCloudsense.clientKey,
"clientSecret": serviceInfo.extras.serviceCloudsense.clientSecret
})
},function (err, res, body) {
if(res.statusCode==404 || res.statusCode==500){
console.log("********res***offerId*************",res.statusCode,offerId);
}
if(err){
// console.log("*****************Errors****************",err);
callback(err,null);
}
callback(null,body);
});
});
return JSON.parse(sendRequestForRelatedProducts());
}
export class Parser {
/*
* This method is used to massage the cloudsense data and respond with the below formate
*
* {
* "catalogueId": "a26O0000000SOS7IAO",
* "price": 1536,
* "name": "IPHONE 6S PLUS",
* "default": "true",
* "color": "Silver",
* "memory": "128GB",
* "contentId": "IPHONE6S128GBSILVER",
* "featured": "true",
* "isOutright": "Outright",
* "brand": "Apple",
* "startdate": "01-09-2016",
* "enddate": "01-09-2017",
* "OS": "iOS",
* "bluetick": true
* }
*
*
*/
public parseCloudsenseData(CloudsenseData:any,isDefaultFlow : boolean):any{
console.log('*******isDefaultFlow********',isDefaultFlow);
let current_Date = moment().format(Constants.DateFormate);
let parseCloudData = function(result,callback){
try{
let microserviceResponse={
"catalogueId" : result.catalogueId,
"catalogueItemId" : result.catalogueItemId,
"outrightPrice" : result.cscfga__One_Off_Charge__c,
"displayName" : result.name,
"currentDate" : current_Date,
"recurringPrice" : result.cscfga__Recurring_Charge__c
};
let key = Constants.Name;
let value = Constants.Value;
//fetch the list of attributes.
for(let att of result.attributes){
parsePropertiesFile(att,microserviceResponse,key,value);
}
debugger;
//fetching the relatedProducts Data. if there are relatedProducts calling the endpoint to get more details
if(!isDefaultFlow && result.relatedProducts!= undefined && result.relatedProducts!=null && result.relatedProducts.length>0 ){
let microserviceRelatedProductArray=[];
// debugger;
// result.catalogueItemId = 'caf71d86-bca3-4bed-a2d5-b233305b8e76'
let relatedProductArray = requestRelatedProductsInfo(result.catalogueItemId);
for(let relatedProduct of relatedProductArray.results){
// for(let relatedProduct of relatedProductArray){
let finalRelatedProduct ={
"productId" : relatedProduct.productId,
"name" : relatedProduct.name,
"sku" : relatedProduct.sku,
"productType" : relatedProduct.productType,
"productSubType" : relatedProduct.productSubType,
"outrightPrice" : relatedProduct.cscfga__One_Off_Charge__c,
"recurringPrice" : relatedProduct.cscfga__Recurring_Charge__c,
"contentId" : '',
"mobileRepaymnetOption":''
};
//This loop is there to find the content_id among available attributes dynamically.
for(let att of relatedProduct.attributes){
parsePropertiesFile(att,finalRelatedProduct,key,value);
}
microserviceRelatedProductArray.push(finalRelatedProduct);
} // end of for loop.
microserviceResponse.relatedProducts =microserviceRelatedProductArray;
}//end of if. ( view details flow).
// if(!isDefaultFlow && result.relatedProducts!= undefined && result.relatedProducts!=null && result.relatedProducts.length>0 ) {
// var catalogueItemIdArray = [];
// catalogueItemIdArray.push(result.catalogueId);
// }
return callback(null,microserviceResponse);
}catch(error){
// log.debug("************error block**********",error);
return callback(error,null);
}
};
let microServiceOutput;
//calling the parseCloudData method asynchronusly for each element in the array.
async.map(CloudsenseData.results, parseCloudData ,function (error,result){
if(error){
// console.log("***************Error***************",error);
microServiceOutput = {
"code":1005,
"message": "The downstream is not available"
};
return microServiceOutput;
}
microServiceOutput = result;
});
return microServiceOutput;
}//End of parseCloudsenseData();
}
I have a website made with Polymer that when you log in, it returns you in the session storage a key userData with values docID, name, surname and surname2, and then it enters to the platform. Those values are stored in the session storage of the browser.
I want to use those values except the docID and bring it to my code for plot it in the log in view/page, but I don't know how to use the session storage to take those parameters.
I made a fake user but with local storage that works with last time of connection but I don't know how to use it with session and receiving data from a website. This is my script:
Polymer({
date: null,
timeDate: null,
keyStorage: 'lastConnection',
ready: function(){
this.storageDate();
this.timeDate = this.getLastDateConnection();
this.storageUser();
this.fakeUserName = this.getUser();
},
getLastDateConnection: function(){
var date = new Date(parseInt(localStorage.getItem(this.keyStorage)));
return [date.getHours(),('0'+date.getMinutes()).slice(-2)].join(':');
},
storageDate: function(){
localStorage.setItem(this.keyStorage, +new Date);
},
getUser: function(){
var name = [localStorage.getItem("firstname") + " " + localStorage.getItem("lastname")];
return name;
},
storageUser:function(){
localStorage.setItem("lastname", "Vader");
localStorage.setItem("firstname", "Dark");
}
});
I want to do something similar except I have to storage the user data with session storage and from a website (I don't know the info until someone gets logged), so I suppose that I shouldn't do a setItem and just made a getItem receiving the key "userData" from the website. Any help/idea? Thanks!
PS: Maybe should I store the user info in my local storage after I receive the userData from the session storage if I want to keep the username? What I want to do is something equal to what Google do with our gmail accounts (you logg-in and when you want to enter again, it stores your account).
Ok, so I think I got it.
in the ready function is to make the call of the function that storages the session storage with:
ready: function(){
this.setData();
this.myUser = this.storageUser();
},
setData: function() {
sessionStorage.setItem("userData",userData);
},
and then storage the session storage in the local making a parse of the object:
storageUser: function(){
var userData = sessionStorage.getItem("userData");
var myObject = JSON.parse(userData);
var userName = [myObject.name + " " + myObject.surname];
return userName;
},
This is working on principle.
I know this is an old post but for new people who land on this page, this session storage element might be of help. It's behaviour is exactly like local storage.
<!--
#license
Copyright (c) 2015 The PlatinumIndustries.pl. All rights reserved.
This code may only be used under the BSD style license.
-->
<link rel="import" href="../polymer/polymer.html">
<!--
Element access to Web Storage API (window.sessionStorage).
Keeps `value` property in sync with sessionStorage.
Value is saved as json by default.
### Usage:
`Ss-sample` will automatically save changes to its value.
<dom-module id="ls-sample">
<iron-sessionstorage name="my-app-storage"
value="{{cartoon}}"
on-iron-sessionstorage-load-empty="initializeDefaultCartoon"
></iron-sessionstorage>
</dom-module>
<script>
Polymer({
is: 'ls-sample',
properties: {
cartoon: {
type: Object
}
},
// initializes default if nothing has been stored
initializeDefaultCartoon: function() {
this.cartoon = {
name: "Mickey",
hasEars: true
}
},
// use path set api to propagate changes to sessionstorage
makeModifications: function() {
this.set('cartoon.name', "Minions");
this.set('cartoon.hasEars', false);
}
});
</script>
### Tech notes:
* * `value.*` is observed, and saved on modifications. You must use
path change notifification methods such as `set()` to modify value
for changes to be observed.
* * Set `auto-save-disabled` to prevent automatic saving.
* * Value is saved as JSON by default.
* * To delete a key, set value to null
* Element listens to StorageAPI `storage` event, and will reload upon receiving it.
* **Warning**: do not bind value to sub-properties until Polymer
[bug 1550](https://github.com/Polymer/polymer/issues/1550)
is resolved. session storage will be blown away.
`<iron-sessionstorage value="{{foo.bar}}"` will cause **data loss**.
#demo demo/index.html
#hero hero.svg
-->
<dom-module id="iron-sessionstorage"></dom-module>
<script>
Polymer({
is: 'iron-sessionstorage',
properties: {
/**
* SessionStorage item key
*/
name: {
type: String,
value: ''
},
/**
* The data associated with this storage.
* If set to null item will be deleted.
* #type {*}
*/
value: {
type: Object,
notify: true
},
/**
* If true: do not convert value to JSON on save/load
*/
useRaw: {
type: Boolean,
value: false
},
/**
* Value will not be saved automatically if true. You'll have to do it manually with `save()`
*/
autoSaveDisabled: {
type: Boolean,
value: false
},
/**
* Last error encountered while saving/loading items
*/
errorMessage: {
type: String,
notify: true
},
/** True if value has been loaded */
_loaded: {
type: Boolean,
value: false
}
},
observers: [
'_debounceReload(name,useRaw)',
'_trySaveValue(autoSaveDisabled)',
'_trySaveValue(value.*)'
],
ready: function() {
this._boundHandleStorage = this._handleStorage.bind(this);
},
attached: function() {
window.addEventListener('storage', this._boundHandleStorage);
},
detached: function() {
window.removeEventListener('storage', this._boundHandleStorage);
},
_handleStorage: function(ev) {
if (ev.key == this.name) {
this._load(true);
}
},
_trySaveValue: function() {
if (this._doNotSave) {
return;
}
if (this._loaded && !this.autoSaveDisabled) {
this.debounce('save', this.save);
}
},
_debounceReload: function() {
this.debounce('reload', this.reload);
},
/**
* Loads the value again. Use if you modify
* sessionStorage using DOM calls, and want to
* keep this element in sync.
*/
reload: function() {
this._loaded = false;
this._load();
},
/**
* loads value from session storage
* #param {boolean=} externalChange true if loading changes from a different window
*/
_load: function(externalChange) {
var v = window.sessionStorage.getItem(this.name);
if (v === null) {
this._loaded = true;
this._doNotSave = true; // guard for save watchers
this.value = null;
this._doNotSave = false;
this.fire('iron-sessionstorage-load-empty', { externalChange: externalChange});
} else {
if (!this.useRaw) {
try { // parse value as JSON
v = JSON.parse(v);
} catch(x) {
this.errorMessage = "Could not parse session storage value";
console.error("could not parse sessionstorage value", v);
v = null;
}
}
this._loaded = true;
this._doNotSave = true;
this.value = v;
this._doNotSave = false;
this.fire('iron-sessionstorage-load', { externalChange: externalChange});
}
},
/**
* Saves the value to localStorage. Call to save if autoSaveDisabled is set.
* If `value` is null or undefined, deletes localStorage.
*/
save: function() {
var v = this.useRaw ? this.value : JSON.stringify(this.value);
try {
if (this.value === null || this.value === undefined) {
window.sessionStorage.removeItem(this.name);
} else {
window.sessionStorage.setItem(this.name, /** #type {string} */ (v));
}
}
catch(ex) {
// Happens in Safari incognito mode,
this.errorMessage = ex.message;
console.error("sessionStorage could not be saved. Safari incoginito mode?", ex);
}
}
/**
* Fired when value loads from localStorage.
*
* #event iron-localstorage-load
* #param {{externalChange:boolean}} detail -
* externalChange: true if change occured in different window.
*/
/**
* Fired when loaded value does not exist.
* Event handler can be used to initialize default value.
*
* #event iron-localstorage-load-empty
* #param {{externalChange:boolean}} detail -
* externalChange: true if change occured in different window.
*/
});
</script>
I am trying to use JSDoc in a Backbone Model, so I have the following profile.js file:
/**
A module representing a Profile.
#exports models/profle
#example
// Load module
require(['models/profile'], function(Profile) {
var Myprofile = new Profile();
});
*/
define(['backbone'], function(Backbone) {
/**
#constructor
#requires Backbone
#augments module:Backbone.Model
*/
var Profile = Backbone.Model.extend({
/**
#lends profile.prototype
*/
defaults: {
PIN : null,
is_guest: true,
has_pin: false,
imgSrc: null
},
/**
Validate a Profile
The validate method is passed the model attributes, as well as the options from set or save
#param {attrs} The attributes of the profile
#param {options} The options from set or save
*/
validate: function(attrs, options) {
if (!attrs.name || attrs.name.length == 0)
return 'You must enter a name!';
if (!!attrs.name && attrs.name.length < 1 && attrs.name.length > 24)
return "User name must be between 1 and 24 characters";
if (!attrs.password || attrs.password.length != 4)
return "The pincode has to be four digits";
if (!attrs.password || attrs.password != attrs.confirmPassword)
return "Confirmed pincode does not match";
}
});
return Profile;
});
The problem is that when I do `jsdoc profile.js -d="home/mydocumentation" it generates a warning
>> WARNING: Trying to document validate as a member of undocumented symbol profile.
and it didn't document the validate function, any idea what I am doing wrong?