my home controller has many actions and one of action take datatime as parameter
public ActionResult DateCheck(DateTime? orderdate)
{
return View();
}
i have one action link which is pointing DateCheck action. here it is
#Html.ActionLink("Date route test", "DateCheck", new { orderdate = "12-25-2016" })
i have mention a route for DateCheck action just to pass datetime as route data. here it is
routes.MapRoute(
name: "",
url: "{controller}/{action}/{orderdate}",
defaults: new { controller = "Home", action = "DateCheck", orderdate = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
now the problem is when i start my site from VS2013 IDE then DateCheck action getting called but it suppose to call when user will click on link. so where is the mistake. help me to fix it. thanks
Note that MVC tries to match routes in the order they are defined.
Also, the {orderDate} is defined as UrlParameter.Optional.
So when you start your application, the first request for localhost/Home/Index is matched by the orderDate route: {controller} is "Home", {action} is "Index" and {orderdate} is null. The default route is never applied because a matching route has already been found. And the defaults of the orderDate route basically say "I don't care which controller and action name you passed to me, I will always redirect you to Home/DateCheck".
If the DateCheck action is the only one that accepts an orderDate as route value, change your routing config to reflect this:
routes.MapRoute(
name: "orderDate",
url: "Home/DateCheck/{orderdate}",
defaults: new { controller = "Home", action = "DateCheck", orderdate = UrlParameter.Optional }
);
If you do not expect that users will enter this route directly in the browser, you do not need to define an extra route just to increase readability of the URL. Remove the orderDate route, your URL will then look like this: localhost/Home/DateCheck?orderdate=12-25-2016.
Related
I'm trying to delete a record that is related to the current record loaded using a workflow action script. I've seen other answers to similar questions saying that I can find the internal ID of the related record with a search using the value in the key field as the search parameter. Problem: The N/search module is not available in a workflow action script, which is where I'm currently coding.
To make the question more concrete, my user has pulled up a general ledger account record ('account'), and they're going to delete it. I have an NS bundle that functions as an integrator with a 3rd party piece of software. The NS bundle has a value transformation table that maps the NS account codes to the 3rd party software codes. Each value transformation lives in a custom record ('icvt') created by the bundle, and I need the value transformation record deleted. I was hoping to use N/search to look up the icvt record, but I CAN'T USE SEARCH in a workflow action script.
Help.
Edit: Just realized I think I misunderstood the documentation, and that N/search is available, so my error must be somewhere else.
Edit to add code. This is the search code I was using before I realized the module wasn't available to me:
/**
*#NApiVersion 2.x
* #NScriptType WorkflowActionScript
*/
// Deletes Value Transform related to account deleted.
define(['N/record', 'N/search', 'N/log'], function (record, search, log) {
function wfDeleteICVT(scriptContext) {
var deleted_account = scriptContext.newRecord;
var da_internalID = deleted_account.getValue("id");
var v_da_internalID = da_internalID.toString();
var mySearch = search.create({
type: 'icvt',
filters: [
search.createFilter({
name: 'sourcevalue',
operator: search.Operator.IS,
values: v_da_internalID
})
]
});
//log.debug(v_da_internalID)
var myResultSet = mySearch.run();
var myResultRange = myResultSet.getRange(0,1);
log.debug({title: myResultRange.length, details: myResultSet})
var deleted_icvt = mySearch[0];
var di_icvt = deleted_icvt.id;
deleted_icvt.delete({
type: 'icvt',
id: di_internalID
});
}
return {
onAction : wfDeleteICVT
}
});
If you are able to fetch the ID of the record that needs to be deleted, you can use N/record module with record.delete(options) to delete the desired record.
// Delete a sales order.
var salesOrderRecord = record.delete({
type: record.Type.SALES_ORDER,
id: 88,
});
// Delete an instance of a custom record type with the ID customrecord_feature.
var featureRecord = record.delete({
type: 'customrecord_feature',
id: 3,
});
EDIT-
N/search module works on Workflow Action Scripts. I myself have used it many times. Why don't you create the Saved Search in UI on Netsuite and then Export it as script and use it in your script?
To export - You can use the Chrome extension below.
NetSuite Search Export
Also, I can see you have created filters in your search.create method but you didn't add any columns. That might be the issue.
Let me know.
Here's the final solution that worked. I was completely wrong in my initial assumptions that I couldn't use search, so that was the ultimate solution, although I did take #sayeesh's advice and use a search created through the UI:
/**
*#NApiVersion 2.x
* #NScriptType WorkflowActionScript
*/
// Deletes Value Transform related to account deleted.
define(['N/record', 'N/search', 'N/log'], function (record, search, log) {
function icvtDelete(scriptContext) {
var deleted_account = scriptContext.newRecord; //gets the account record of the current account
var da_internalID = deleted_account.getValue("id"); //gets the internal id of the current account
var v_da_internalID = da_internalID.toString(); //converts the internal id to a string for comparison later
var mySearch = search.load({
id: "customsearch_icvt_search"}); //loads a saved search
var mySearchResult = mySearch.run(); //runs the saved search
var myResults = mySearchResult.getRange(0,1000); //gets the range of results
for(var i in myResults){ //iterates through the results
var result = myResults[i]; //load a result
if(result.getValue('custrecordictransformationvalue') == v_da_internalID) //if the result is the one we're looking for
{
var icvt_to_delete = record.load({
type: 'mycustomrecord',
id: result.getValue('id')
});
log.debug(v_da_internalID, result.getValue('id'));
icvt_to_delete.setValue({fieldId: 'deletionreason', value: 1});
icvt_to_delete.setValue({fieldId: 'deletionreasonmemo', value: 'SS2.0 Delete reason saved using Load/Save'});
icvt_to_delete.save();
record.delete({
type: 'mycustomrecord',
id: result.getValue('id')
});
}
}
}
return {
onAction : icvtDelete
}
});
I have UserEntity and AddressEntity, they are related as OneToOne, that's one user may have only one address. UserEntity has fields firstName, secondName, address. AddressEntity has fields country and city.
If I wanted to update UserEntity without doing it to its relations I would do this:
await entityManager.getRepository(UserEntity)
.createQueryBuilder('users')
.update(UserEntity)
.set(updateUserObject)
.where('users.id = :userId', { userId })
.execute();
where updateUserObject is formed from a request body. That's to say, if I need to update firstName, the object would look like this: { firstName: 'Joe' }. Now what is unclear is how to use that builder if I have the following updateUserObject:
{
firstName: "Bob",
address: {
"city": "Ottawa"
}
}
The official documentation does not address such cases.
You can achieve this using preload and save methods.
Update your UserEntity similar to below:
#Entity('user')
export class UserEntity {
...
#OneToOne(
() => AddressEntity,
{
// Make sure that when you delete or update a user, it will affect the
// corresponding `AddressEntity`
cascade: true,
// Make sure when you use `preload`, `AddressEntity` of the user will also
// return (This means whenever you use any kind of `find` operations on
// `UserEntity`, it would load this entity as well)
eager: true
}
)
#JoinColumn()
address: AddressEntity;
}
Now using entityManager, you can update all the fields that you want using the following way:
const partialUserEntity = {
id: userId,
firstName: "Bob",
address: {
"city": "Ottawa"
}
};
const userRepository = await entityManager.getRepository(UserEntity);
// Here we load the current user entity value from the database and replace
// all the related values from `partialUserEntity`
const updatedUserEntity = userRepository.preload(partialUserEntity);
// Here we update (create if not exists) `updatedUserEntity` to the database
await userRepository.save(updatedUserEntity);
However, you need to make sure that your UserEntity has an AddressEntity associated always. Otherwise, you will have to generate an id for AddressEntity like below before you execute save method.
/*
* If `updatedUserEntity.address.id` is `undefined`
*/
// `generateIDForAddress` is a function which would return an `id`
const generatedIDForAddress = generateIDForAddress();
const partialUserEntity = {
id: userId,
firstName: "Bob",
address: {
"id": generatedIDForAddress,
"city": "Ottawa"
}
};
Please note that under the hood, typeorm will run UPDATE statements separately for UserEntity and AddressEntity. This is just an encapsulation of multiple join statements (when executing preload method) and update statements (when executing save method) such that the developer can easily implement this scenario.
Hope this helps you. Cheers 🍻!
The following function is to return all menu items of a specific type. The types exist in the database but the query is returning no data. Without the query criterion: {type:menuItem}, it returns the data with the the type.
exports.get = async (menuItem) => {
console.log(chalk.green('menuItem', menuItem));
try {
const menu = await Menu.find({type:menuItem});
console.log('menu', menu);
return menu;
} catch(error) {
console.log(error)
}
}
MenuItem logged to the console as shown in the function above produces the following. The problem seem to be with the variable, menuItem, because when I hard-code, {type:'pizza'}, it works.
console.log(chalk.green('menuItem', menuItem));
menuItem 'pizza'
The anuglar query string looks like the following, is there a problem with this:
private menuUrl = '/api/menu?menuItem="pizza"';
Sample data from the database:
{ quantity: 1,
toppings: [ 'chipotle-steak', 'red-onions' ],
_id: 5d163a7ae7179a4e432b501a,
type: 'pizza',
name: 'CHIPOTLE STEAK',
price: 15,
img: 'Chipotle-Steak.png',
}
The key type is used to tell mongoose about the type of that particular field. thats why using type as a field in mongoose schema can sometimes behave ambiguously.
Kindly change type to kind and search with {kind : menuItem} and it should work for you.
Dont forget to update all the docs from type to kind.
To update :
Menu.update({},{$rename : {'type' : 'kind'}},{multi:true})
Then find using kind
const menu = await Menu.find({kind:menuItem});
Silly mistake. The Angular query string had single quotes around pizza:
private menuUrl = "/api/menu?menuItem='pizza'";
It should have been without quotes instead:
private menuUrl = "/api/menu?menuItem=pizza";
I cannot find a way to retrieve data from the server and convert them to model instance. I folloed the instructions here but it's still doesn't work.
Here is my setup:
url for the service: services/foo/barOne. The response is : {"calendar":1352793756534,"objectId":"id2"}
The model is defined as follow:
var myModel = can.Model(
model: function(raw) {
newObject = {id:raw.objectId};
return can.Model.model.call(this,newObject);
},
findOne: {
url: 'services/foo/barOne',
datatype: 'json'
}
)
And here is how I use that:
myBar = myModel.findOne()
myBar.then(function() {
console.log("resolved with arguments:",arguments); //[undefined]
})
I put various log and tracked all of function called, the request is correctly done, and the ajax resolved correctly. The model method is also correct and return an object of type Constructor with the right parameters.
But after that, inside the pipe function of canjs, the result is lost (ie, I got the result undefined when d.resolve.apply(d, arguments) is called)
What is wrong with this scenario ?
I am using canJS with jquery version 1.0.7
I don't think you need a custom converter just for changing the id. You can change it by setting the static id property. Try it like this:
var MyModel = can.Model({
id : 'objectId'
}, {
findOne: 'services/foo/barOne'
});
MyModel.findOne({ id : 'test' }).done(function(model) {
console.log(model);
});
I'd like to implement a search page using Backbone.js. The search parameters are taken from a simple form, and the server knows to parse the query parameters and return a json array of the results. My model looks like this, more or less:
App.Models.SearchResult = Backbone.Model.extend({
urlRoot: '/search'
});
App.Collections.SearchResults = Backbone.Collection.extend({
model: App.Models.SearchResult
});
var results = new App.Collections.SearchResults();
I'd like that every time I perform results.fetch(), the contents of the search form will also be serialized with the GET request. Is there a simple way to add this, or am I doing it the wrong way and should probably be handcoding the request and creating the collection from the returned results:
$.getJSON('/search', { /* search params */ }, function(resp){
// resp is a list of JSON data [ { id: .., name: .. }, { id: .., name: .. }, .... ]
var results = new App.Collections.SearchResults(resp);
// update views, etc.
});
Thoughts?
Backbone.js fetch with parameters answers most of your questions, but I put some here as well.
Add the data parameter to your fetch call, example:
var search_params = {
'key1': 'value1',
'key2': 'value2',
'key3': 'value3',
...
'keyN': 'valueN',
};
App.Collections.SearchResults.fetch({data: $.param(search_params)});
Now your call url has added parameters which you can parse on the server side.
Attention: code simplified and not tested
I think you should split the functionality:
The Search Model
It is a proper resource in your server side. The only action allowed is CREATE.
var Search = Backbone.Model.extend({
url: "/search",
initialize: function(){
this.results = new Results( this.get( "results" ) );
this.trigger( "search:ready", this );
}
});
The Results Collection
It is just in charge of collecting the list of Result models
var Results = Backbone.Collection.extend({
model: Result
});
The Search Form
You see that this View is making the intelligent job, listening to the form.submit, creating a new Search object and sending it to the server to be created. This created mission doesn't mean the Search has to be stored in database, this is the normal creation behavior, but it does not always need to be this way. In our case create a Search means to search the DB looking for the concrete registers.
var SearchView = Backbone.View.extend({
events: {
"submit form" : "createSearch"
},
createSearch: function(){
// You can use things like this
// http://stackoverflow.com/questions/1184624/convert-form-data-to-js-object-with-jquery
// to authomat this process
var search = new Search({
field_1: this.$el.find( "input.field_1" ).val(),
field_2: this.$el.find( "input.field_2" ).val(),
});
// You can listen to the "search:ready" event
search.on( "search:ready", this.renderResults, this )
// this is when a POST request is sent to the server
// to the URL `/search` with all the search information packaged
search.save();
},
renderResults: function( search ){
// use search.results to render the results on your own way
}
});
I think this kind of solution is very clean, elegant, intuitive and very extensible.
Found a very simple solution - override the url() function in the collection:
App.Collections.SearchResults = Backbone.Collection.extend({
urlRoot: '/search',
url: function() {
// send the url along with the serialized query params
return this.urlRoot + "?" + $("#search-form").formSerialize();
}
});
Hopefully this doesn't horrify anyone who has a bit more Backbone / Javascript skills than myself.
It seems the current version of Backbone (or maybe jQuery) automatically stringifies the data value, so there is no need to call $.param anymore.
The following lines produce the same result:
collection.fetch({data: {filter:'abc', page:1}});
collection.fetch({data: $.param({filter:'abc', page:1})});
The querystring will be filter=abc&page=1.
EDIT: This should have been a comment, rather than answer.