Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I know I can't save data to file with javascript, but is there any solution to create configuration file (JSON) on local file system where I can write data, make some changes like add or remove object and save this. I don't want lose my new data when i next time starts my app. Any ideas?
Thanks for help.
UPDATE
I want to use it on different computers.
You could write yourself a SettingsService to read and write the data via the localstorage:
class SettingsEntry {
constructor(public key: string, public value: any) { }
}
export class SettingsService {
private SETTINGS_KEY = "__SETTINGS__";
private _settings: Array<SettingsEntry>;
constructor() {
let settings = localStorage.getItem(this.SETTINGS_KEY);
if (settings && settings != undefined) {
this._settings = JSON.parse(settings);
}
else {
this._settings = [];
this.save();
}
}
private indexOf(key: string): number {
for (let i = 0; i < this._settings.length; i++) {
if (this._settings[i].key == key) {
return i;
}
}
return -1;
}
private save() {
localStorage.setItem(this.SETTINGS_KEY, JSON.stringify(this._settings));
}
get(key: string) {
let index: number = this.indexOf(key);
if (index >= 0) {
return this._settings[index].value;
}
return null;
}
set(key: string, value: any) {
let index: number = this.indexOf(key);
if (index >= 0) {
this._settings[index].value = value;
}
else {
this._settings.push(new SettingsEntry(key, value));
}
this.save();
}
}
Use it like this in your components or services:
_settingsService.set("time", new Date());
let time = _settingsService.get("time");
Working Plunker for example usage
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 days ago.
Improve this question
I'm working in a project to create a knife in 3 parts and I want to create something like this. I don't really know if it's possible.
//selector
const imgBlade = document.querySelector('.piece__blade');
const imgPart = document.querySelector('.piece__part');
const imgMatter = document.querySelector('.piece__matter');
// here only 3 parts to create the knife but i have alot of more thant that
const shinyBladeImagePath = /img/products/shinyblade.png;
const centralePartImagePath = /img/products/centralePart.png;
const woodCentralePartPath = /img/products/woodCentralePart.png;
class piece {
constructor(name, info, path) {
this.name = name;
this.info = info;
this.path = path;
}
}
let shinyBlade = new piece('SB', 'Shiny Blade', shinyBladeImgPath);
let centralePart = new piece('CP', 'Centrale Part', centralePartImagePath);
let woodCentralePart = new piece('W01', 'Wood Centrale Part', woodCentralePartPath);
class knife {
constructor(blade, part, matter) {
this.blade = blade;
this.part = part;
this.matter = matter;
}
}
let firstKnife = new knife(shinyBlade, centralePart, woodCentralePartPath);
// here I want to create a function to create a dynamic "object" :
function showKnife(event) {
// Here I want to change path with on a click event
imgBlade.src = ;
imgPiece.src = ;
imgMatter.src = ;
}
shinyBladeTitle.addEventListener('click', () => {
showKnife.imgBlade.blade.path;
// here I want to click on a title option and change the imgBlade.src on my function
});
centralePartTitle.addEventListener('click', () => {
showKnife.imgPiece.piece.path;
// here I want to click on a title option and change the imgPiece.src on my function
});
woodTitle.addEventListener('click', () => {
showKnife.imgMatter.matter.path;
// here I want to click on a title option and change the imgPiece.src on my function
});
<div>
<img alt="Blade" src="/img/products/BLANK.png">
<img alt="Part" src="/img/products/BLANK.png">
<img alt="Piece" src="/img/products/BLANK.png">
</div>
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I want to create an json structure with data which will get from an api call. I can generate the structure by using following code. But how can I restructure the code to remove nested call of function and loops.
var temp = {
applications: []
};
api.getApplications(conceptId)
.then((applications) => {
for (var i = 0; i < applications.length; i++) {
(function(indexOfAppArr) {
let applicationId = applications[indexOfAppArr].id;
temp.applications.push({
id: applicationId,
databases: []
});
api.getDbs(conceptId, applicationId)
.then(databases => {
for (var j = 0; j < databases.length; j++) {
(function(indexOfDatabasArr) {
let databaseid = databases[indexOfDatabasArr].id;
temp.applications[indexOfAppArr].databases.push({
id: databaseid,
tabels: []
});
api.
getSchema(conceptId,
applicationId, databaseid).
then(function(schemas) {
for (var k = 0; k < schemas.length; k++) {
(function(indexofschemaarr) {
let schemaid = schemas[indexofschemaarr].id;
api.getTable(conceptId, schemaid)
.then(function(tables) {
console.log(tables);
})
})(k)
}
})
})(j)
}
})
})(i)
}
})
Here is the JSON structure which i want to create.
{
applications:[{
id:'',
databases:[{
id:'',
tabels:[
{
id:'',
columnId:''
}
]
}]
}]
};
If you read a little you'll actually learn how to do it. I personally haven't had the need to learn it yet but it sounded interesting, here is an excellent website that I found for you:
https://javascript.info/promise-chaining
it explains there how to "restructure" the code you are asking by putting it in less words:
loadScript("/article/promise-chaining/one.js").then(function(script1) {
loadScript("/article/promise-chaining/two.js").then(function(script2) {
loadScript("/article/promise-chaining/three.js").then(function(script3) {
// this function has access to variables script1, script2 and script3
one();
two();
three();
});
});
});
I'm sure it only takes less than 30 mts of reading. Best of luck!
Requirements when clicking the Qualify button in the Lead entity form:
Do not create an Opportunity
Retain original CRM qualify-lead JavaScript
Detect duplicates and show duplicate detection form for leads
Redirect to contact, either merged or created version, when done
The easiest approach is to create a plugin running on Pre-Validation for message "QualifyLead". In this plugin you simply have to set CreateOpportunity input property to false. So it would look like:
public void Execute(IServiceProvider serviceProvider)
{
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
context.InputParameters["CreateOpportunity"] = false;
}
Or you can go with more fancy way:
public void Execute(IServiceProvider serviceProvider)
{
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
var qualifyRequest = new QualifyLeadRequest();
qualifyRequest.Parameters = context.InputParameters;
qualifyRequest.CreateOpportunity = false;
}
Remember that it should be Pre-Validation to work correctly. Doing it like that allows you to remain with existing "Qualify" button, without any JavaScript modifications.
So Pawel Gradecki already posted how to prevent CRM from creating an Opportunity when a Lead is qualified. The tricky part is to make the UI/client refresh or redirect to the contact, as CRM does nothing if no Opportunity is created.
Before we begin, Pawel pointed out that
some code is not supported, so be careful during upgrades
I don't have experience with any other versions than CRM 2015, but he writes that there are better ways to do this in CRM 2016, so upgrade if you can. This is a fix that's easy to implement now and easy to remove after you've upgraded.
Add a JavaScript-resource and register it in the Lead form's OnSave event. The code below is in TypeScript. TypeScript-output (js-version) is at the end of this answer.
function OnSave(executionContext: ExecutionContext | undefined) {
let eventArgs = executionContext && executionContext.getEventArgs()
if (!eventArgs || eventArgs.isDefaultPrevented() || eventArgs.getSaveMode() !== Xrm.SaveMode.qualify)
return
// Override the callback that's executed when the duplicate detection form is closed after selecting which contact to merge with.
// This callback is not executed if the form is cancelled.
let originalCallback = Mscrm.LeadCommandActions.performActionAfterHandleLeadDuplication
Mscrm.LeadCommandActions.performActionAfterHandleLeadDuplication = (returnValue) => {
originalCallback(returnValue)
RedirectToContact()
}
// Because Opportunities isn't created, and CRM only redirects if an opportunity is created upon lead qualification,
// we have to write custom code to redirect to the contact instead
RedirectToContact()
}
// CRM doesn't tell us when the contact is created, since its qualifyLead callback does nothing unless it finds an opportunity to redirect to.
// This function tries to redirect whenever the contact is created
function RedirectToContact(retryCount = 0) {
if (retryCount === 10)
return Xrm.Utility.alertDialog("Could not redirect you to the contact. Perhaps something went wrong while CRM tried to create it. Please try again or contact the nerds in the IT department.")
setTimeout(() => {
if ($("iframe[src*=dup_warning]", parent.document).length)
return // Return if the duplicate detection form is visible. This function is called again when it's closed
let leadId = Xrm.Page.data.entity.getId()
$.getJSON(Xrm.Page.context.getClientUrl() + `/XRMServices/2011/OrganizationData.svc/LeadSet(guid'${leadId}')?$select=ParentContactId`)
.then(r => {
if (!r.d.ParentContactId.Id)
return RedirectToContact(retryCount + 1)
Xrm.Utility.openEntityForm("contact", r.d.ParentContactId.Id)
})
.fail((_, __, err) => Xrm.Utility.alertDialog(`Something went wrong. Please try again or contact the IT-department.\n\nGuru meditation:\n${err}`))
}, 1000)
}
TypeScript definitions:
declare var Mscrm: Mscrm
interface Mscrm {
LeadCommandActions: LeadCommandActions
}
interface LeadCommandActions {
performActionAfterHandleLeadDuplication: { (returnValue: any): void }
}
declare var Xrm: Xrm
interface Xrm {
Page: Page
SaveMode: typeof SaveModeEnum
Utility: Utility
}
interface Utility {
alertDialog(message: string): void
openEntityForm(name: string, id?: string): Object
}
interface ExecutionContext {
getEventArgs(): SaveEventArgs
}
interface SaveEventArgs {
getSaveMode(): SaveModeEnum
isDefaultPrevented(): boolean
}
interface Page {
context: Context
data: Data
}
interface Context {
getClientUrl(): string
}
interface Data {
entity: Entity
}
interface Entity {
getId(): string
}
declare enum SaveModeEnum {
qualify
}
TypeScript-output:
function OnSave(executionContext) {
var eventArgs = executionContext && executionContext.getEventArgs();
if (!eventArgs || eventArgs.isDefaultPrevented() || eventArgs.getSaveMode() !== Xrm.SaveMode.qualify)
return;
var originalCallback = Mscrm.LeadCommandActions.performActionAfterHandleLeadDuplication;
Mscrm.LeadCommandActions.performActionAfterHandleLeadDuplication = function (returnValue) {
originalCallback(returnValue);
RedirectToContact();
};
RedirectToContact();
}
function RedirectToContact(retryCount) {
if (retryCount === void 0) { retryCount = 0; }
if (retryCount === 10)
return Xrm.Utility.alertDialog("Could not redirect you to the contact. Perhaps something went wrong while CRM tried to create it. Please try again or contact the nerds in the IT department.");
setTimeout(function () {
if ($("iframe[src*=dup_warning]", parent.document).length)
return;
var leadId = Xrm.Page.data.entity.getId();
$.getJSON(Xrm.Page.context.getClientUrl() + ("/XRMServices/2011/OrganizationData.svc/LeadSet(guid'" + leadId + "')?$select=ParentContactId"))
.then(function (r) {
if (!r.d.ParentContactId.Id)
return RedirectToContact(retryCount + 1);
Xrm.Utility.openEntityForm("contact", r.d.ParentContactId.Id);
})
.fail(function (_, __, err) { return Xrm.Utility.alertDialog("Something went wrong. Please try again or contact the IT-department.\n\nGuru meditation:\n" + err); });
}, 1000);
}
There is a fully functional and supported solution posted over at our Thrives blog: https://www.thrives.be/dynamics-crm/functional/lead-qualification-well-skip-that-opportunity.
Basically we combine the plugin modification as mentioned by Pawel with a Client Side redirect (using only supported JavaScript) afterwards:
function RefreshOnQualify(eventContext) {
if (eventContext != null && eventContext.getEventArgs() != null) {
if (eventContext.getEventArgs().getSaveMode() == 16) {
setTimeout(function () {
Xrm.Page.data.refresh(false).then(function () {
var contactId = Xrm.Page.getAttribute("parentcontactid").getValue();
if (contactId != null && contactId.length > 0) {
Xrm.Utility.openEntityForm(contactId[0].entityType, contactId[0].id)
}
}, function (error) { console.log(error) });;
}, 1500);
}
}
}
Following scenario.
I wrote a angular2 application with material2.
In my SideNav is a search input field. When a user types in it, he is redirected (via routing) to the search component, while the searched word is handed over as a routing parameter.
The search component shows all pages of the application, which contain the searched word (index in the background). Once the user clicks on the entry, he's redirected to this page, and the searched word is appended as a query parameter. I'm now trying to highlight all appearances of the searchword on the page, the user gets redirected to. At the moment i'm doing this:
subscription: ISubscription;
searchTerm: string;
constructor(private router: Router, private elementRef: ElementRef) {}
ngOnInit(): void {
this.subscription = this.router.routerState.queryParams.subscribe(queryParams => {
let searchTerm = queryParams['searchTerm'];
if (searchTerm) {
this.searchTerm = searchTerm;
} else {
this.searchTerm = null;
}
});
}
ngAfterContentInit(): void {
if (this.searchTerm && isStaticDoc) {
let regExp = new RegExp(`(${this.searchTerm})`, 'i');
this.highlightWords(this.elementRef.nativeElement, regExp);
}
}
ngOnDestroy(): void {
this.subscription.unsubscribe();
}
highlightWords(node, regExp: RegExp) {
if (!node || ! regExp) {
return;
}
if (node.nodeType === 3) {
let regs = regExp.exec(node.nodeValue);
if (regs) {
let match = document.createElement('span');
match.appendChild(document.createTextNode(regs[0]));
match.classList.add('search-hl');
let after = node.splitText(regs.index);
after.nodeValue = after.nodeValue.substring(regs[0].length);
node.parentNode.insertBefore(match, after);
}
} else if (node.hasChildNodes()) {
for (let i = 0; i < node.childNodes.length; i++) {
this.highlightWords(node.childNodes[i], regExp);
}
}
}
Now the issue is, that i get an error RangeError: Maximum call stack size exceeded, which might be a hint, that the recursion level is way to deep.
I've already tried to use 3rd party libraries, bot non of them is really made to be used from angular2 and on top, the written code isn't that difficult... but its not working.
Any ideas how to stage beneath the maximum call stack size following the same or an similar approach?
tl;dr trying to highlight all appearances of searchTerm(which is passed over as a queryParam) on the page -> my approach (see code) is not
working due to max call stack size.
Edit: Using rc4 atm, upgrading soon, but this shouldn't be an issue (i guess)
Thanks to user3791775 I've come up with an solution.
highlightWords(html: string, searchTerm: string): string {
let regExp = new RegExp(`(${searchTerm})`, 'i');
let results = regExp.exec(html);
if (results) {
let before = html.substr(0, results.index);
let after = html.substr(results.index + searchTerm.length);
let indexOpenTag = before.lastIndexOf('<');
let indexCloseTag = before.lastIndexOf('>');
let indexOpenTagAfter = after.indexOf('<');
let indexCloseTagAfter = after.indexOf('>');
if (indexOpenTag <= indexCloseTag && indexOpenTagAfter <= indexCloseTagAfter) {
return `${before}<span class="search-hl">${results[0]}</span>${this.highlightWords(after, searchTerm)}`;
} else {
return `${before}${results[0]}${this.highlightWords(after, searchTerm)}`;
}
} else {
return html;
}
}
This can be used the following way
let ref = document.getElementById('my-highlicht-content');
ref.innerHtml = this.highlightWords(ref.innerHtml, this.searchTerm)
Thanks for helping!
Edit:
Had another edgecase, which made it necessary to inspect the part after the keyword as well. Updated my example.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I'm using the below javascript code in my appery.io app. I keep getting an error which states the following:
6/25/2014 9:37:35 PM: Script All_Users_Data: TypeError: Cannot read property '_id' of undefined ( # 52 : 33 ) -> if (all_photo[i].the_user._id == id) {
Please help me identify the bug. I'm attempting to pull data from 3 collections, sync them up by _id from a 'users' collection and then output user profile type information.
var all_users = eval(DatabaseUser.query('52895ecce4b056c5e94f34f9'));
var all_profiles = eval(Collection.query('52895ecce4b056c5e94f34f9', 'profile'));
var all_status = eval(Collection.query('52895ecce4b056c5e94f34f9', 'Status'));
var all_photo = eval(Collection.query('52895ecce4b056c5e94f34f9', 'photo'));
// loop on all users
for (var i=0;i<all_users.length;i++)
{
// call function to search for user profile and then add first name to current user item
getProfile(all_users[i]._id, all_users[i]);
// call function to search for user status and then add last status to current user item
getstatus(all_users[i]._id, all_users[i]);
getphoto(all_users[i]._id, all_users[i]);
}
// function get user item and user id and find user profile by its id and update it
function getProfile(id,curUser)
{
var found = false;
for (var i = 0; i < all_profiles.length; i++) {
// if cur user id = profile id assign profile name to the user
if (all_profiles[i].the_user._id == id)
{
curUser.firstName = all_profiles[i].firstName;
curUser.university = all_profiles[i].university ;
found = true;
}
}
if (!found)
{
curUser.f_name = "";
}
}
// function get user item and user id and find user status by its id and update it
function getstatus(id, curUser) {
var found = false;
for (var i = 0; i < all_status.length; i++) {
if (all_status[i].the_user._id == id) {
curUser.status = all_status[i].status;
found = true;
}
}
if (!found) {
curUser.status = "";
}
}
function getphoto(id, curUser) {
var found = false;
for (var i = 0; i < all_photo.length; i++) {
if (all_photo[i].the_user._id == id) {
curUser.photo = all_photo[i].photo;
found = true;
}
}
if (!found) {
curUser.photo = "";
}
}
// return full user data updated wih status and first name
response.success(JSON.stringify(all_users), "application/json");
It means this is undefined:
all_photo[i].the_user
So as it is undefined, it most definitely doesn't have the property _id, as undefined objects have no properties, because they are undefined.
Does that define the source of the problem?
--
Use your browser console - it helps:
console.log(all_photo);
Then you can check out what is happening with that object and what properties it does have after you eval it.