How can i format Telephone number from xxxxxxxxxx to (xxx) xxx-xxxx
in telerik MVC Grid .client.template.
I tried something like this. which is not working
string formatPattern = #"(\d{3})(\d{3})(\d{4})";
columns.Bound(e=>e.ID)
.ClientTemplate(Html.Raw(String.Format("{0:###-###-####}", "<#= Telephone #>") + "<br />" + Regex.Replace("<#= Fax #>", formatPattern, "($1) $2-$3")).ToString()).Title("Phone / Fax");
I tried both ways String.format and Regex.Replace
I also tried $.telerik.formatString('{0:###-###-####}'<#= telephone =>)
but no use.
I got this done with the below code.
In Telerik Grid bound the column like this
.ClientTemplate("<#= GetPhoneFaxTemplate(data) #>").Title("Phone / Fax");
And the Scripts goes like this
function GetPhoneFaxTemplate(data) {
if (isNumeric(data.Telephone)) {
var phone = $.telerik.formatString('{0:(###) ###-####}', Number(data.Telephone))
}
else {
phone = data.Telephone;
}
if (isNumeric(data.Fax)) {
var fax = $.telerik.formatString('{0:(###) ###-####}', Number(data.Fax))
}
else {
fax = data.Fax;
}
template = phone + "<br />" + fax;
return template;
}
function isNumeric(n) {
return !isNaN(parseFloat(n)) && isFinite(n);
}
That's it yureka!
Related
I'm developing a web application using MVC5 and I use output cache attribute on one of my actions.
the problem is after multiple page visits, my page will have binary content that looks like this:
page screenshot
there's my source:
[OutputCache(Duration = 86400, Location = OutputCacheLocation.ServerAndClient,VaryByParam = "ID;slug")]
[SeoOptionsFilter]
public ActionResult CourseDetail(int ID, string slug)
{
var courseComplexObject =
_courseRepository.GetCourseDetail(ID, slug);
var course = courseComplexObject.Model;
TempData["breadcrumb"] = BreadcrumbViewBuilder
.New().Home().Courses()
.AddMore(course.CategoryName, "/Category/" + course.CategoryId.ToString() + "/" + course.CategorySlug)
.AddMore(course.Name, "/CourseDetails/" + course.CourceId.ToString() + "/" + course.Slug + ".aspx",
true)
.Build();
//TODO: What if course is null
SetViewBagIfUserIsRegistered(course, ID);
TempData["CourseVideoCatOn"] = GetCourseVideoCategory(ID);
TempData["CourseID"] = ID;
TempData.Keep();
// Response.Cache.SetOmitVaryStar(true);
return View(courseComplexObject.Model);
}
I commented my custom action filter [SeoOptionsFilter]
but the result already has errors.
this error occurs randomly in page visits
We have multiple Typewriter .tst templates in our project, and would like to share some common logic/methods between them. Is there a way to do this?
You can use T4 templates to generate the Typewriter templates. Put the code inside a reusable T4 template (*.ttinclude) and create tt-files to pass parameters to the rendering method of this base template.
(I use a Visual Studio extension for File nesting.)
Each tt-file looks something like this;
<## template debug="true" hostSpecific="true" #>
<## output extension=".tst" #>
<## include file="..\ModelsTemplate.ttinclude" #>
<# this.ModelsTemplate_Render("UserSettings"); #>
...and my ttinclude file looks like this (it is a bit project specific, but I included it all so that anyone who wants to try it out can easily get something working);
<## IntelliSenseLanguage processor="tangibleT4Editor" language="C#" #>
<#+
void ModelsTemplate_Render(string #subnamespace) {
ModelsTemplate_Render("MyApp.ViewData", #subnamespace);
}
void ModelsTemplate_Render(string #mainnamespace, string #subnamespace) {
string renderedMainNamespace = #mainnamespace;
#>
// <auto-generated>
// This code was generated by a tool.
// Template: <#= Host.TemplateFile #>
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
${
// Enable extension methods by adding using Typewriter.Extensions.*
using Typewriter.Extensions.Types;
using System.Text.RegularExpressions;
Template(Settings settings)
{
settings.IncludeProject("MyApp.ViewData");
}
static string DebugInfo = "";
string PrintDebugInfo(File f){
if (string.IsNullOrEmpty(DebugInfo)) {
return "";
}
return "/*" + Environment.NewLine + "Template debug info: " + DebugInfo + Environment.NewLine + "*/";
}
string BaseClassFullPath(Class baseClass)
{
//DebugInfo = DebugInfo + Environment.NewLine + "baseClass.FullName:" + baseClass.FullName;
var result = baseClass.Name;
// Until we find a better way to handle implementations of generic base classes...
result = result.Replace("<bool?>", "<boolean>");
result = result.Replace("<int?>", "<number>");
result = result.Replace("<long?>", "<number>");
result = result.Replace("<decimal?>", "<number>");
result = result.Replace("<double?>", "<number>");
result = result.Replace("<System.Double>", "<number>");
result = result.Replace("<System.Double?>", "<number>");
result = result.Replace("<System.DateTime?>", "<Date>");
return result;
}
string NullableFilter(string typeName)
{
return typeName.Replace("?", "");
}
string TypeFilteredPath(Type type)
{
//DebugInfo = DebugInfo + Environment.NewLine + "type:" + type.FullName + " - genericType:" + type.Unwrap().FullName;
return NullableFilter(type.Name);
}
string TypeFiltered(Type type)
{
if (type.IsEnumerable)
{
var genericType = type.Unwrap();
if (!genericType.FullName.StartsWith("System"))
{
return TypeFilteredPath(genericType)+"[]";
}
}
return TypeFilteredPath(type);
}
string PropertyTypeFiltered(Property prop)
{
return TypeFiltered(prop.Type);
}
string ImplementedInterfaces(Class c){
if (!c.Interfaces.Any()){
return string.Empty;
}
return "implements " + string.Join(", ", c.Interfaces.Select(x => x.FullName));
}
string ExtendedInterfaces(Interface i){
if (!i.Interfaces.Any()){
return string.Empty;
}
return "extends " + string.Join(", ", i.Interfaces.Select(x => x.FullName));
}
string DescriptionAttributeValue(Attribute a){
if (!a.FullName.Contains("DescriptionAttribute")){
return string.Empty;
}
return a.Value;
}
string GetPropertyDefinitionWithScope(Property p){
var definition = GetPropertyDefinition(p);
if (definition != "")
return "public " + definition;
else
return definition;
}
string GetPropertyDefinition(Property p){
var ignoreAttribute = p.Attributes.SingleOrDefault(x => x.FullName.Contains("TypeScriptIgnoreMemberAttribute"));
if (ignoreAttribute != null)
return "";
var typeAttribute = p.Attributes.SingleOrDefault(x => x.FullName.Contains("TypeScriptTypeAttribute"));
if (typeAttribute != null) {
return p.name + ": " + typeAttribute.Value + ";";
}
return p.name + ": " + TypeFiltered(p.Type) + ";";
}
string WriteImports(Class theClass){
//return "import { ViewDataEntity } from '../common/ViewDataEntity';";
var list = new List<string>();
var typesToImport = theClass.Properties.Select(x => x.Type.Unwrap()).Where(x => x.Namespace.Contains("MyApp.ViewData.")).ToList();
if (theClass.BaseClass?.Namespace.Contains("MyApp.ViewData.") == true)
typesToImport.Add(theClass.BaseClass);
foreach (var impType in typesToImport)
{
var modules = impType.Namespace.Replace("MyApp.ViewData.", "").Split('.').ToList();
string modPart = string.Join("/", modules.Select(x => CamelCase(x)));
list.Add($"import {{ {impType.Name} }} from '../{modPart}/{impType.Name}';");
}
return string.Join(Environment.NewLine, list.Distinct());
}
string CamelCase(string value){
return value.First().ToString().ToLower() + value.Substring(1);
}
}//namespace <#= renderedMainNamespace #>.<#= #subnamespace #> {
$Classes(c => c.Namespace.StartsWith("<#= #mainnamespace #>.<#= #subnamespace #>"))[
$WriteImports
export class $Name$TypeParameters $BaseClass[extends $BaseClassFullPath ] $ImplementedInterfaces {$Properties[
$GetPropertyDefinitionWithScope]
}]
$Interfaces(<#= #mainnamespace #>.<#= #subnamespace #>.*)[
export interface $Name $ExtendedInterfaces {
$Properties[
$GetPropertyDefinition]
}]
$Enums(<#= #mainnamespace #>.<#= #subnamespace #>.*)[
export class $Name {
$Values[// $Value - "$Attributes[$Value]"
static $Name = "$Name";
]
}]
$PrintDebugInfo
//}<#+
}
#>
Unfortunately there's no way to share code in tst templates. Support for this will probably come in a future version though.
I am working around with Salesforce and force.com API and metadata API, version 36.
I can create a custom field in a Lead object but by default I can see it's hidden and this means I cannot create a new Lead with these custom fields because it returns a bad request (400 status code).
Is there any way by Code to set the custom field Visible?
public boolean createCustomExtTextField(String name, LoginResult metadataLoginResult, int length) {
boolean success = false;
CustomField cs = new CustomField();
cs.setFullName("Lead."+name+"__c");
cs.setLabel("Custom"+name+"Field");
cs.setType(FieldType.LongTextArea);
cs.setLength(length);
cs.setVisibleLines(50); // max 50
try {
MetadataConnection metadataConnection = createMetadataConnection(metadataLoginResult);
SaveResult[] results = metadataConnection.createMetadata(new Metadata[] { cs });
for (SaveResult r : results) {
if (r.isSuccess()) {
success = true;
} else {
System.out.println("Errors were encountered while creating " + r.getFullName());
for (com.sforce.soap.metadata.Error e : r.getErrors()) {
System.out.println("Error message: " + e.getMessage());
System.out.println("Status code: " + e.getStatusCode());
}
}
}
} catch (ConnectionException e) {
e.printStackTrace();
}
return success;
}
I am googling a lot and don't find something that actually helped. So, any hints are welcomed. Thank you.
Finally found a solution to this. I final one for me was to make all custom fields REQUIRED.
CustomField cs = new CustomField();
cs.setFullName("Lead.YourCompanyName" + name + "__c");
cs.setLabel("YourCompanyName" + name);
cs.setRequired(true);
...
com.sforce.soap.enterprise.LoginResult metadataLoginResult = operations.loginToMetadata(username, password, "https://login.salesforce.com/services/Soap/c/36.0");
...
private boolean createFieldInMetadata(LoginResult metadataLoginResult, CustomField cs) {
boolean success = false;
try {
MetadataConnection metadataConnection = createMetadataConnection(metadataLoginResult);
SaveResult[] results = metadataConnection.createMetadata(new Metadata[] { cs });
for (SaveResult r : results) {
if (r.isSuccess()) {
success = true;
} else {
System.out.println("Errors were encountered while creating " + r.getFullName());
for (com.sforce.soap.metadata.Error e : r.getErrors()) {
System.out.println("Error message: " + e.getMessage());
System.out.println("Status code: " + e.getStatusCode());
}
}
}
} catch (Exception e) {
}
return success;
}
And so it will appear in the page layout. Very important to know, a required field cannot have just an empty value set, it must be something. So if not all custom fields are required in your logic and you wanna avoid the entire process of unzipping page layout and zipping it back (however it may be done) just add "N/A" or any char at choice to the required by code but not your project custom fields.
I managed to make the custom Field Level Security visible for "Admin" profile but not Field Accessability to visible. The latter is untested.
I am doing a fairly simple query for contact records using dynamic soql using the following method:
public PageReference contactSearch() {
contactResultSetSize = 0;
if(!String.isEmpty(firstname) || !String.isEmpty(lastname) || !String.isEmpty(company)) {
string soql = 'Select firstname, lastname, account.Name, account.BillingStreet, account.BillingCity, account.BillingState, account.BillingPostalCode From Contact';
String whereClause = '';
if(!String.isEmpty(firstname)) {
whereClause = ' Where firstname like \'%' + firstname + '%\'';
}
if(!String.isEmpty(lastname)) {
if(!String.isEmpty(firstname)) {
whereClause += ' AND lastname like \'%' + lastname + '%\'';
}
else {
whereClause = ' Where lastname like \'%' + lastname + '%\'';
}
}
if(!String.isEmpty(company)) {
if(!String.isEmpty(firstname) || !String.isEmpty(lastname)) {
whereClause += ' AND account.Name like \'%' + company + '%\'';
}
else {
whereClause = ' Where account.Name like \'%' + company + '%\'';
}
}
soql = soql + whereClause;
List<Contact> searchResults = Database.query(soql);
contactResultSetSize = searchResults.size();
if(contactLinesForPage == null) {
contactLinesForPage = new List<ContactWrapper>();
}
for(Contact c : searchResults) {
contactLinesForPage.add(new ContactWrapper(contactLinesForPage.size(), c, ''));
}
}
return null;
}
I am using a wrapper class and contactLinesForPage is a list of my wrapper object:
public List<ContactWrapper> contactLinesForPage {get; set;}
As a user does multiple searches, I don't want to re-add records to the searchResults list. How can I check if a record already exists in my object so I don't have duplicate records returned in the search?
Thanks for any help.
Or you could use a map. Add the ContactWrapper objects to the map. The key to the map is an id. If they add a duplicate contact it will simply overwrite the one already there. Your code would simply be
aMap.put(cw.id, cw); // one line eliminates duplicates.
When you want the list of ContactWrappers, simply return aMap.values();
If you want to abstract the behavior of maintaining the collection of Contacts, create a ContactCollection class and hide the implementation in there. This would provide something more reusable as well as a good pattern for similar situations.
Just add a check if contactLinesForPage allready contains this contact. Something like this:
for(Contact c : searchResults) {
Boolean toInsert = true;
for(ContactWrapper cw : contactLinesForPage){
if(cw.contact.Id == c.Id){
toInsert=false;
}
}
if(toInsert){
contactLinesForPage.add(new ContactWrapper(contactLinesForPage.size(), c, ''));
}
}
My company has an app that they got off of the app exchange(Note: before I started) that allowed you to follow or unfollow large number of cases/accounts/opportunities etc in salesforce.com. Supposedly it worked before and now it isn't working. I need an idea of what is wrong with the code for each button. If I can't fix them, any ideas for a replacement app? The app is no longer on the app exchange any more.
here's the code for the follow button:
{!REQUIRESCRIPT("/soap/ajax/18.0/connection.js")}
//EDIT THE FOLLOWING LINE TO ALTER THE CODE FOR OTHER OBJECTS. USE THE PICKLISTS ABOVE TO SELECT FIELD TYPE = $ObjectType AND THE OBJECT NAME THEN REPLACE "$ObjectType.Case" WITH YOUR NEW OBJECT NAME
var records = {!GETRECORDIDS( $ObjectType.Case)};
function LBox() {
var box = new parent.SimpleDialog("steve"+Math.random(), true);
parent.box = box;`
box.setTitle("Follow Records");
box.createDialog();
box.setWidth(220);
box.setContentInnerHTML("<img src='/img/loading32.gif' alt='' /> Running");
box.setupDefaultButtons();`
box.show();
}
function CBox(){
box.setContentInnerHTML("You are now following "+follow_count+" records<br /><br />Close");
}
if (records[0] == null) {
alert("Please select at least one record.");
}
else {
var follow_count = 0;
LBox();
for (var i = 0; i < records.length; i++){
var fol=new sforce.SObject("EntitySubscription");
fol.ParentId = records[i];
fol.SubscriberId = '{!User.Id}';
try{
sforce.connection.create([fol]);
follow_count++;
}
catch(e){
alert(e);
}
}
CBox();
}
here's the unfollow button:
{!REQUIRESCRIPT("/soap/ajax/18.0/connection.js")}
// EDIT THE FOLLOWING LINE TO ALTER THE CODE FOR OTHER OBJECTS. USE THE PICKLISTS ABOVE TO SELECT FIELD TYPE = $ObjectType AND THE OBJECT NAME THEN REPLACE "$ObjectType.Case" WITH YOUR NEW OBJECT NAME
var records = {!GETRECORDIDS( $ObjectType.Case)};
// display running message popup
function LBox() {
var box = new parent.SimpleDialog("steve"+Math.random(), true);
parent.box = box;`
box.setTitle("Unfollow Records");
box.createDialog();
box.setWidth(220);
box.setContentInnerHTML("<img src='/img/loading32.gif' alt='' /> Running");
box.setupDefaultButtons();
box.show();
}
// display output message
function CBox(){
if (unfollow_count < records.length)
box.setContentInnerHTML("You have now unfollowed "+unfollow_count+" records. You were not following the other selected records. <br /><br />Close");
else
box.setContentInnerHTML("You have now unfollowed "+unfollow_count+" records. <br /><br />Close");
}
if (records[0] == null) {
alert("Please select at least one record.");
}
else {
var unfollow_count = 0;`
LBox();
try {
// find following records
var searchstring = "SELECT Id FROM EntitySubscription WHERE (ParentId IN (";
for (var i = 0; i < records.length - 1; i++) {
searchstring += "'" + records[i] + "',";
}
searchstring += "'" + records[records.length - 1] + "') AND SubscriberId ='{!User.Id}')";
var resultRecords = sforce.connection.query(searchstring).getArray("records");
// delete following records
var recordIds = [];
for (var i = 0; i < resultRecords.length; i++) {
recordIds.push(resultRecords[i].Id);
unfollow_count++;
}
sforce.connection.deleteIds(recordIds);
} catch(e) {
alert(e);
}
CBox();
}
The first error message has to do with permissions, I don't get this error because I have admin rights, the second error is only on the account tab's button. I'm more worried about the permissions problem, is there anything there about permissions. Any help is great!
I think the issue is a throttle in SFDC, you are limited to following only a certain number of records per user. If this app was designed as you described to mass-follow records, it's possible your hitting that throttle, which is kind of the impression I get from the error your co-worker is receiving about at most 1000, also if it worked before, it would make sense that you have maxed out a limit for the org/user
Queries on EntitySubscription by users who aren't system admins must contain a LIMIT. If you change the query code in the button to the following it should work:
// find following records
var searchstring = "SELECT Id FROM EntitySubscription WHERE (ParentId IN (";
for (var i = 0; i < records.length - 1; i++) {
searchstring += "'" + records[i] + "',";
}
searchstring += "'" + records[records.length - 1] + "') AND SubscriberId ='{!User.Id}') LIMIT 1000";