I am looking at hiding Email on Leads Page Layout.
I am including it in a section already with a visualforce page but PageLayout doesn't detect that and still requires it to be on the layout.
Is there a way to remove it from the PageLayout?
I have read that you can edit a picklist but didn't find any solid examples of doing that. I also read about Field Level Accessibility but I don't think that's the way to go since everyone is part of the same role and I am only excluding the detail based off if you're the owner. I have also tried javascript but since my visualforce page is loaded in an iframe I can't access the parent document of the iframe to be able to hide or remove the value from email while viewing not as the owner.
Any thoughts would be appreciated.
Try hiding the field with JavaScript stored in a Custom Button. In the On-Click JavaScript for the button, you can include code that will be run on page load by jQuery that hides the Email field. You can then hide the actual button as well. Very much a hack approach, but it should work.
Here's some code to put in the On-Click JavaScript button (modified from Daniel Llewellyn's blog post and mgsmith's force2b blog post). Hopefully this should get you jump-started. I didn't include any code on how to hide the Email field, but you said you were already trying it through your Visualforce page, so I figured I'd leave that part to you. Cheers!
var interval;
//The main function that does all the work
function appendScript() {
// Include core jQuery library by injecting it into the DOM
var script= document.createElement('script');
script.type= 'text/javascript';
script.src= 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js';
head.appendChild(script);
// It takes a second to load, so put in a delay
// (we don't want to try and reference the script
// before it is actually loaded, so we store the interval
// in a global variable, and set up an interval.
// this interval dealio. This will keep running
// until jQuery has been found to be loaded and then
//clears the interval so it doesn't keep running.
interval=self.setInterval(function(){
//Check to see if jQuery has loaded
if(jQuery) {
//if jQuery has loaded, clear the interval
window.clearInterval(interval);
// Hide the Email field
// Hide the custom button
var btnName = 'buttonName';
try{
var buttons = parent.document.getElementsByName(btnName);
for (var i=0; i < buttons.length; i++) {
buttons[i].className="btnDisabled ";
buttons[i].disabled=true;
buttons[i].type='hidden';
}
} catch(e) {
// var ee = e.message || 0; alert('Error: \n\n'+e+'\n'+ee);
}
}
}, 300);
}
appendScript();
Related
In my angular app, there are two pages (list & checkout). In the list page the user could search for an item and the searched item will be displayed and then the user can select the item and continue to checkout.
From the checkout page the user could return back to list page, and at that time all the items in the list page should be same as how it was left before.
For implementing this feature, my code is
on moving from list page to checkout page, all the scope data are stored in a service
returnsService.setScopeData($scope);
And on returning back from checkout page to list page, this saved data are retrieved from service and assigned to scope variables.
var restoreScopeData = returnsService.getScopeData();
if (restoreScopeData) {
for (var key in restoreScopeData) {
if (key.charAt(0) != '$') {
$scope[key] = restoreScopeData[key];
}
}
}
This works fine to an extend, and I can see the list page same as how I left it.
But the problem is, now I'm not able to search for new item in the list page.
When ever a search happens, the items are populated to $scope.listSearch and they are displayed in html {{listSearch}}.
In the error case also,
I can see the new search data getting assigned to the $scope.listSearch, but the HTML binding is not happening.
I tried calling $scope.$apply() after the search assigning, but still not working.
Storing complete scope isn't good idea. You can just store the vars you need. Also, you can use localStorage for this.
As I understood, making new call is not an option, so you can try use $timeout.
$timeout(function() {
$scope.listSearch = myValue;
});
Instead of doing this, you may for localStorage or sessionStorage as suggsted by John.
You may check below link for example
https://www.codeproject.com/Articles/1015515/Working-With-Client-Side-Local-Storage
How can I automatically close the $cordovaInAppBrowser when it goes to my website and returns content "OK"? I would like to do this to avoid displaying the close button in the browser window.
Does anyone know how I can achieve this?
I did find the website that can solve this for those who also need to self close the browser in some condition.Here is the reference link : https://developer.salesforce.com/forums/?id=906F00000009ALSIA2
sample coding:
authWindow.addEventListener('loadstop', function(e) {
var loc = e.url;
//when url is changed check if the url contains your specific callbackURL
if (loc.search(data.callbackURL) >= 0) {
//at this point close your inapp browser
//you will land on the index page within your application.
authWindow.close();
//your code after successful authentication
}
});
you can use something like a timeout function or other than that a even listener other than i would suggest make a custom plugin and use it. The solution provided by #Blouraf is very hacky.
I did find some documentation on the cordova plugin that recommends a listener.
I'm working on a ExtJS.Grid that uses a Ext.data.Store with jsonp proxy and Ext.PagingToolbar to control paging. It's all working fine.
But some users are complaining that they further browse pages, leave the grid, and when they come back they are back to page 1. They want "the grid to remember" the page they were and starts on it.
I use a Ext.onReady(function(){},false); to define all components and another Ext.onReady(function(){}); to create the grid with a store.loadPage(1); to make the first load after everything is done.
If I could listen to some event from the Ext.PagingToolbar, when a new load happens, and capture the page it was used, I could pehaps store it in some cookie or something, and retrieve it to load that page again.
I looked on http://docs.sencha.com/extjs/4.1.3/#!/api/Ext.toolbar.Paging and found no event that could be used. Anybody has any idea of where I could do it?
You can track the change event of the Ext.toolbar.Paging and remember the currentPage in a cookie.
pagingtoolbar.on('change', function(pb, pageData) {
Ext.util.Cookies.set('lastGridPage', pageData.currentPage, new Date('1/1/2016'));
});
And setup your grid to load that page on afterrender
grid.on('afterrender', function() {
var pageNumber = Ext.util.Cookies.get('lastGridPage') || 1;
grid.store.loadPage(pageNumber);
})
I'm new to AngularJS and hoping someone can help me get my head round this please!
I'm developing a web e-reader that pulls in pages of HTML content dynamically. So far, I'm doing that with an $http AJAX call and binding it in with 'ng-bind-html-unsafe' (the HTML is our own, simply served from a directory on the same server. I have control over the HTML so I could do this differently if needs be). So each time the user presses previous/next, the controller simply fetches in the previous/next page of HTML and switches that in the model - that works great.
But next I need to augment this dynamic HTML with user additions, e.g. comments and highlights. They need to appear where the user adds them, e.g. a comment would most likely sit underneath a particular paragraph.
With JQuery I guess I would give each of the HTML elements its own ID and associate each bit of user-generated content with a particular ID. Then I could manipulate the DOM myself, for example adding each comment under its associated element.
What's the right approach with AngularJS, since the principle seems to be to avoid direct DOM manipulation altogether?
I could see how it could be done by defining the HTML content as separate elements in the model, having individual JavaScript objects for each paragraph, header, image, etc. But that would basically be defining DOM-like data in JavaScript - and that feels quite wrong and messy...
Use an "ng-include" and dynamically bind a src attribute from the controller. Adding dynamic, user generated content is as adding the binding variables to your html. Following is angular code that implements previous/next buttons that dynamically loads html templates and populates them with the user added comments. At the bottom is a link to a fully functional jsfiddle.
angular.module('app',[]).controller('controller', function($scope){
var change;
change = function(){
$scope.src = $scope.page + '.html';
};
$scope.page = 1;
$scope.items = [];
change();
$scope.submit = function(text){
$scope.items.push(text);
};
$scope.next = function () {
if($scope.page < 3){
$scope.page++;
change();
}
};
$scope.previous = function () {
if($scope.page > 1){
$scope.page--;
change();
}
};
});
http://jsfiddle.net/jwanga/rnL7c/
Anyone know how to have the calendar view expanded all by default?? Seen a lot of information on how to do this with SP 2007 but not SP 2010.
Kuldeep, thanks for this script! I have modified it slightly to expand all rows of the calendar by removing the break and checking to see if the anchor text is "collapse". If it's not "collapse", a click is executed. Note that you only need to click on one item per row. Otherwise, you might toggle back to collapsed.
Another problematic side effect of adding the CEWP to the Calendar page is that you lose the Change View dropdown. You have to use the calendar ribbon to change views.
I would also like to find a more robust solution, but here is my slighly improved solution:
<script type="text/javascript">
_spBodyOnLoadFunctionNames.push("myFuncAfterLoad");
function myFuncAfterLoad() {
var oldCalendarNotify4a = SP.UI.ApplicationPages.CalendarNotify.$4a;
SP.UI.ApplicationPages.CalendarNotify.$4a = function () {
oldCalendarNotify4a();
myFuncToExpandCalendar();
}
}
function myFuncToExpandCalendar() {
try {
var aTags = document.getElementsByTagName('A');
for (i = 0; i < aTags.length; i++) {
if ((aTags[i].evtid == "expand_collapse") && (aTags[i].innerText != "collapse")) {
(aTags[i]).click();
}
}
}
catch (err) {
alert(err.message);
}
}
</script>
Not the best approach but it works, add the following script on your page in CEWP or inline:
<script type="text/javascript">
_spBodyOnLoadFunctionNames.push("myFuncafterLoad");
function myFuncafterLoad(){var OldCalendarNotify4a = SP.UI.ApplicationPages.CalendarNotify.$4a;SP.UI.ApplicationPages.CalendarNotify.$4a = function (){myFunctoExpandCalendar();OldCalendarNotify4a();}}
function myFunctoExpandCalendar(){try{var aTags=document.getElementsByTagName('A');for(i=0;i<aTags.length;i++){try{if(aTags[i].evtid=="expand_collapse"){aTags[i].click();break;}}catch(err){ alert('Bad Call at' + aTags[i].href);}}}catch(err){alert(err.message);}}</script>
What it does is after the calendar is loaded it searches for the first expand link and simulates a click.
I had to use the traditional Javascript as I cannot trigger click using JQuery, because the click method is not added using JQuery.
Let me know if somefine finds a better solution.
Two options for this one. Stick one or the other of the following in a CEWP.
The first one will override the function that is used to determine how many items to display before showing the expand/collapse link. I have set this to 100 in the example below to ensure that in my use case, I never even see the expand/collapse buttons and I always get every item rendered all the time.
<script type="text/javascript">
_spBodyOnLoadFunctionNames.push('WaitForCalendarToLoad');
function WaitForCalendarToLoad()
{
SP.UI.ApplicationPages.SummaryItemRenderer.prototype.$2u = function ()
{
ULSvSp: ;
if (!this.$1A_1) this.$1A_1 = 100;
return this.$1A_1
}
}
</script>
The second option overrides the calendar notify event, so that after all the items are rendered, the script will find the first calendar instance, and call it's expand all function. This will ensure every cell is expanded by default but will still show the collapse links.
<script type="text/javascript">
_spBodyOnLoadFunctionNames.push('WaitForCalendarToLoad');
function WaitForCalendarToLoad()
{
var old$4a = SP.UI.ApplicationPages.CalendarNotify.$4a;
SP.UI.ApplicationPages.CalendarNotify.$4a = function ()
{
old$4a();
ctrl = SP.UI.ApplicationPages.CalendarInstanceRepository.firstInstance();
if (ctrl) {
ctrl.expandAll();
}
}
}
</script>
I'm using this (in 2013):
<style>
.ms-cal-nav { display:none; }
</style>
<script type="text/javascript">
LoadSodByKey("SP.UI.ApplicationPages.Calendar.js", function () {
window.setTimeout(ExpandCalendar, 500);
});
function ExpandCalendar() {
// expand always
$('.ms-cal-nav:has(img[src$="/expandbttn.gif"])').each(function() { this.click(); });
window.setTimeout(ExpandCalendar, 1000);
}
</script>
It runs every second, which isn't great, but seems to do the job
So based on the original solutions provided by Andrew Peacock (presumably for SP2010), I was able to use those as a stating point to put together a working solution for SP2016.
The big difference seems to be that CalendarNotify is deprecated in SP2016, which causes many of the SP2010-based solutions not to work in newer versions. Then there are additional complications if using overlaid calendars; it seems that the HTML elements for events on overlaid calendars are not rendered until very late in the page load process - even waiting on the last sourced script on the page (sp.ui.socialribbon.js) using SP.SOD does not wait long enough for those to be available. I believe this is why most, if not all of the solutions for SP2016 calendars that rely on these being available must end up using either setTimeout() or setInterval(). In our case, for the second solution, we need to wait until all overlaid events have been rendered on the calendar before calling the calendar's expandAll() function or it won't work.
With that said, these are the two SP2016-compatible solutions I came up with, based off the original SP2010 solutions noted above. The first removes the expand/collapse link altogether and ensures that the calendar will always be expanded to show all events.
The first method overrides the built-in function that sets the "collapse item limit" (the number of items that will force the "expand/collapse" link to appear).
<script type="text/javascript">
function setCalendarCollapseItemLimit() {
// Configure the calendar's "collapse item limit" so that it always shows
// all items by default and never collapses them.
SP.UI.ApplicationPages.SummaryItemRenderer.prototype.$3V_1 = function() {
ULSvSp:;
if(!this.$1B_1) {
// This sets the "collapse item limit" to 100 events
this.$1B_1 = 100;
}
return this.$1B_1;
}
}
// Call our function once the necessary script is loaded (sp.ui.applicationpages.calendar.js in this case).
ExecuteOrDelayUntilScriptLoaded(setCalendarCollapseItemLimit, "sp.ui.applicationpages.calendar.js");
</script>
The advantage of this method is that it stays expanded even if new events are added to the calendar after the page loads, with no need to manually re-expand or refresh the page. The downside is that this solution may need updating after an upgrade since the obfuscated variable names may change (this example was confirmed working w/ SP2016 w/ the 7/2017 CU - v16.0.4561.1000).
The second method calls the calendar's built-in expandAll() function once all the events are displayed. The advantage of this method is that it leaves the "collapse" link available for the user to collapse the calendar if desired.
<script type="text/javascript">
function expandAllCalendarItems() {
var cal = SP.UI.ApplicationPages.CalendarInstanceRepository.firstInstance();
if (cal) {
cal.expandAll();
return true;
} else {
return false;
}
}
// We need to use setInterval() here so that the calendar will be expanded when it becomes available and
// after any overlaid calendar events have been rendered. An interval of 1400 seems to be sufficient for this.
// We store the return value so that we can clear it (stop the loop) once we’ve successfully expanded it.
var expItemsInterval = setInterval(function() {
var retVal = expandAllCalendarItems();
if (retVal === true) {
// Calendar was expanded - clear interval
clearInterval(expItemsInterval);
}
}, 1400);
</script>
I'm not a huge fan of this solution though since it has a couple big downsides. One is that the calendar will re-collapse if a new event is added to it after the page is loaded. More importantly, however, is the fact that we are relying on the interval being long enough to wait for all overlaid calendar events to be rendered on the page (if using calendar overlays). Therefore we have a sort of race condition here; an interval of 1400 seems to be long enough in my testing for it to work properly, but theoretically if the overlaid events take too long to render, this solution might not work. If not using overlaid calendars then this should not be an issue.
A more proper solution would probably be to use something like a MutationObserver to watch for new elements being added to the page (specifically, divs with a class of .ms-acal-mdiv), and call expandAll() again if a new one is detected. This would also solve the problem of re-expanding the calendar after a new event is added.
All in all, if showing the "collapse" link to the user is not required, I prefer the first solution. I think its the cleanest and most foolproof, since it does not rely on setInterval() and works with both regular and overlaid calendars.
Big thanks to Andrew Peacock for the original solutions here; those put me on the right track for figuring these out for SP2016.
*EDIT: Removed the jQuery dependency since it was unnecessary, and added script tags around the code. This would need to be implemented via SharePoint Designer, right under the PlaceHolderMain tag (using a SEWP or CEWP would probably work as well but I didn't test using those methods).
function expandCalendar()
{
var calendar = SP.UI.ApplicationPages.CalendarInstanceRepository.firstInstance();
if (calendar && typeof calendar.expandAll === 'function') {
calendar.expandAll();
}