Duplicating script and incrementing id names to dynamically add input content - javascript

I am currently working on a website to easily modify css properties and animate using jquery. The page will then output the code for the user to copy and paste into their work.
I am wanting to dynamically add input fields so users can enter their own parameters in "keyframes" for the animation.
I was wondering if there is a way to have a button to create the new elements and the jquery to have it operate. Currently I have tried setting a variables value to increment with the button then have a "for" loop to create the new keyframe elements.
Is there a way to append the previous keyframes with new keyframes
this is a sample of the things I need to set when creating the DOM nodes for the input fields, but the main issue I am having is incrementing the value of "i" and duplicating the code only once.
//////////TOP TEXT INPUT///////////
var newTop = document.createElement('input')
newTop.type = "text"
newTop.id ="animation_" + i + "_top" // i = 1
newTop.size="10"
newTop.value="100"
newTop.name="animation_" + i +"_top" // i = 1
newTop.textContent = "top";
var refTopSibling = document.getElementById('frame_1')
var refTopParent = refTopSibling.parentNode
refTopParent.appendChild(newTop)
//////////TOP TEXT INPUT///////////
var newLeft = document.createElement('input')
newLeft.type = "text"
newLeft.id ="animation_" + i + "_left" // i = 2
newLeft.size="10"
newLeft.value="100"
newLeft.name="animation_" + i +"_left" // i = 2
newLeft.textContent = "left";
var refTopSibling = document.getElementById("animation_" + i + "_top")
var refTopParent = refTopSibling.parentNode
refTopParent.appendChild(newLeft)
Regards,
Andrew
EDIT--------------------------
Thanks for the replies. Unfotunately it's a little large for JS fiddle. I'm only a noob so this may not be the most elegant way to do it, but I used an if statement to increment the variables current value on each press... unfortunately it's not dynamic but I have enough options to allow 11 keyframes of animation that can be dynamically added to the DOM.
function addFrame(){
var n;
if (document.getElementById('frame_1')){n=2};
if (document.getElementById('frame_2')){n=3};
if (document.getElementById('frame_3')){n=4};
if (document.getElementById('frame_4')){n=5};
if (document.getElementById('frame_5')){n=6};
if (document.getElementById('frame_6')){n=7};
if (document.getElementById('frame_7')){n=8};
if (document.getElementById('frame_8')){n=9};
if (document.getElementById('frame_9')){n=10};
if (document.getElementById('frame_10')){n=11};
//rest of the code here
}
Now to figure out a way to draw svg dynamically and animate it with user inputs ;-)

This isn't necessarily the best implementation but I believe it meets your requirements.
function SampleObject(position, i)
{
this.posString = "new" + position;
$(this[this.posString] = document.createElement("input"))
.css({ type: "text",
id: "animation_" + i + "_" + position,
size: "10" ,
value: "100" ,
name: "animation_" + i +"_" + position,
textContent: position
});
$("#frame_1").parent().append(el);
}
//Public methods
SampleObject.prototype.getInput = function()
{
return this[this.posString];
}
//Static members
SampleObject.set = [];
//Static methods
SampleObject.new = function(position);
{
this.set.push(new SampleObject(position, this.set.length + 1));
}
//Quick test
SampleObject.new("top");
jQuery rewrite aside this does three actions, albeit the last might be surplus to requirement.
1) Rather than write a new function for every position the constructor of the object takes a position string (any string would be fine but for your objective position seems apt). The string is appended to "new" to form the "new" that is used to create an object member named in accordance with the current multi-function approach in the post that stores the new input object - personally I think the member naming is redundant but I don't know the project. The object has a get method for returning the input form.
2) Using the static "Sample.new" method (which takes a position parameter) a new SampleObject which has an index value of 1 + (static member) SampleObject.set, the set variable is used to store the new objects as they are created. This might not be necessary but I imagine you'll want to interact with them later or attach event.
As for the "frame_" if statements
$("[id^=frame_]").length() + 1
Assuming that frames are always created iteratively this will return the appropriate value for n.

Related

How do I update the value of a custom attribute (enum-of-strings) in SFCC via code?

Requirement: I want to update the value of a custom attribute (name: badges) (type: enum-of-strings) for a Product via code. I want to set the value "bestSeller" as selected. How should I do that update because the code below is not working?
Screenshot of the Custom Attribute in Business Manager
Code snippet:
function updateBestSeller() {
var ProductMgr = require('dw/catalog/ProductMgr');
var Site = require('dw/system/Site');
var UUIDUtils = require('dw/util/UUIDUtils');
var CustomObjectMgr = require('dw/object/CustomObjectMgr');
var currentSite = Site.getCurrent();
var bestSellerOrderUnits = Object.hasOwnProperty.call(currentSite.preferences.custom, 'bestSellerOrderUnits') ? currentSite.getCustomPreferenceValue('bestSellerOrderUnits') : 0;
try {
Transaction.wrap(function () {
var count = 1;
var products = ProductMgr.queryAllSiteProducts();sni
var HashSet = require('dw/util/HashSet');
var badges = new HashSet();
if (products.count > 0) {
while (products.hasNext() && count < 5) {
var product = products.next();
var badges = [];
badges.push('bestSeller');
if (Object.hasOwnProperty.call(product.custom, 'badges')) {
product.custom.badges = badges
}
count++;
Logger.debug('{0}',product.ID);
}
}
products.close();
});
} catch (ex) {
Logger.error(ex.toString());
return new Status(Status.ERROR, 'ERROR', 'UPDATE failed');
}
return new Status(Status.OK, 'OK', 'UPDATE successful');
}
I think what is probably happening here is that your attempt to validate that a product has a badges key in the product.custom attribute collection is failing. This prevents the update from occurring.
I suggest removing the condition around the following line:
product.custom.badges = badges;
If that line were to not execute, then the update to the database would never occur.
The way custom attributes work is that they will never exist until a value is set for that attribute for a given persistent object. (eg: Product) So checking to see if it exists via something like: 'badges' in product.custom (which is the recommended way) will often be false even when the custom attribute definition exists because many products have never had a badge value set. Once an object has had a value set to a particular custom attribute even if it is now set to null then it will exist.
Additionally, there are some other issues with the code that may be causing problems. One example is defining the badges variable twice within the same scope. Another example is sni that is placed at the end of the line where you define the products variable. This is likely causing an error in your code. Finally, it is a good practice to avoid the use of the queryAllSiteProducts method if you can. An alternative may be to use the ProductSearchModel instead; This may not always meet your need, but it is a good idea to rule it out before resorting to queryAllSiteProducts for performance reasons.
Something else to consider is that if badges currently has any selected values, you'll be overwriting those values with the code you have today. Consider setting badges initially to [] then check to see if there is a value for that product by doing:
if ('badges' in product.custom && !empty(product.custom.badges) {
badges = product.custom.badges;
}

Phaser: Instantiate class by string reference

I am working on a "manager" for selecting what crop shall be placed on a certain plot. Every crop has a completely different design and therefor their own class/object. However instead of writting >40 different lines that will instantiate that class I would like 1 line that simply contains the string that matches the exact name of a class and then run it. That way my code will stay clean. I have tried some stuff but never managed to get it done. Usually resulting in an the following error:
TypeError: this.crop is not a constructor
The code I am attempting to run
export default class CropManager extends Phaser.Group {
constructor (game, className, plotId) {
super(game)
this.x = 0
this.y = 0
this.plotId = plotId
this.className = className
this.cropHandler(this.className)
}
// Defines which class to call
cropHandler (className) {
const ActualClass = 'plot' + className
this.cropclasses = { ActualClass: ActualClass}
this.crop = this.cropclasses[ActualClass]
this.classRun = new this.crop(this.game, this.x, this.y, this.plotId)
this.add(this.classRun)
}
}
Note every crop their classname = crop+cropname (cropCarrots, cropCows, etc)
Rethink the way you're storing key-value pairs in this.cropclasses. The way it's done now, it's going to have 'ActualClass' as the key and 'plotNameOfTheClass' (or whatever 'plot' + className produces) as the value, thus, when accessing it later as an array, this.crop comes out undefined since there isn't a 'plotNameOfTheClass' key in the map.

I'm trying to use jquery to create a div containing columns but I can't get my array to format correctly

I have an array that contains dates. and for some reason I can't get it to show on my screen I've been debugging for a few days now and I've tracked it down to a single line, but the line has worked before and I can't figure out what the issue might be.
The array looks like this:
var selectItems =
[ "05-26-2017", "06-02-2017", "06-09-2017",
"06-16-2017", "06-23-2017", "06-30-2017", "07-07-2017", "07-14-2017",
"07-21-2017", "07-28-2017"...];
It's passed as an argument from another function, but that's how it's showing in console.log().
I might be going about this the wrong way, maybe even a lot further around then I need to but this is what I've come up with:
1. function setTHead(selectItems) {
2 var formatString;
3. for (var x = 0; x < 12; x++) {
4. formatString = selectItems[x].replace(/[^0-9/-]/g, "").toString();
5. console.log(selectItems);
6. $('#datTab').append("<div id='col" + x + "' class='column'>'" + formatString + "'</div>");
7. }
8. }
the array up top is what's showing from the console.log 5 lines down.
the sixth line is what is seeming to give me issues. Nothing is put on the page at all.
I'm getting a console error saying:
jQuery.Deferred exception: selectItems is undefined setTHead#http://localhost/mySite/script.js:136:9
startUp2#http://localhost/mySite/script.js:146:5
#http://localhost/mySite/table.php:19:9
mightThrow#http://localhost/mySite/lib/jquery.js:3586:52
resolve/</process<#http://localhost/mySite/lib/jquery.js:3654:49
setTimeout handler*resolve/<#http://localhost/mySite/lib/jquery.js:3692:37
fire#http://localhost/mySite/lib/jquery.js:3320:30
fireWith#http://localhost/mySite/lib/jquery.js:3450:29
fire#http://localhost/mySite/lib/jquery.js:3458:21
fire#http://localhost/mySite/lib/jquery.js:3320:30
fireWith#http://localhost/mySite/lib/jquery.js:3450:29
ready#http://localhost/mySite/lib/jquery.js:3923:13
completed#http://localhost/mySite/lib/jquery.js:3933:9
EventListener.handleEvent*#http://localhost/mySite/lib/jquery.js:3949:9
#http://localhost/mySite/lib/jquery.js:39:9
#http://localhost/mySite/lib/jquery.js:17:3
undefined
followed by:
TypeError: selectItems is undefined
and thats pointing to line 6.
if anyone has any advice I would be very much appreciative. Thank you in advance.
EDIT: A little more code:
function startTblView(defSel) {
if (defSel === true) {
setCookie('defSel', true, 7);
} else{
setCookie('defSel', false, 7);
}
saveSelected();
window.open('table.php', '_self');
defSel = getCookie('defSel');
if (defSel) {
selectItems = getDefDates();
}else {
selectItems = reGetSelected();
}
setTHead(selectItems);
}
defSel, is a boolean passed from my last page stating whether I'm doing a default view or a custom view, the custom view is passed from saveSelected();
saveSelected is a function for just saving the selected global value as a cookie so I can pull it out on the next page.
getDefDates pulls the default values for the array
reGetSelected, gets the selected array from the cookie.
I apologize for wonky naming conventions. I'm the only one working on this site and I'm just making sure the names don't overlap.
You can do this :
HTML code
<div id="datTab"></div>
JS code
var selectItems =
[ "05-26-2017", "06-02-2017", "06-09-2017",
"06-16-2017", "06-23-2017", "06-30-2017", "07-07-2017", "07-14-2017",
"07-21-2017", "07-28-2017"];
function setTHead(selectItems) {
var formatString;
$.each( selectItems, function( index, value ){
formatString = value.replace(/[^0-9/-]/g, "").toString();
$('#datTab').append("<div id='col" + index + "' class='column'>'" + value + "'</div>");
});
};
You can use $.each, its better than 'for' with javascript.
The .each() method is designed to make DOM looping constructs concise
and less error-prone. When called it iterates over the DOM elements
that are part of the jQuery object. Each time the callback runs, it is
passed the current loop iteration, beginning from 0. More importantly,
the callback is fired in the context of the current DOM element, so
the keyword this refers to the element.
I did a JsFiddle
Here.

Can mxGraph use UUID to replace the id generated default with integer type?

The id of mxCell is used integer type with increment 1 each time by default, but we want to replace it to UUID type. What's the better way to overwrite the default function? Thanks
mxGraphModel.prototype.createId = function(cell)
{
var id = this.nextId;
this.nextId++;
return this.prefix + id + this.postfix;
};
I have changed the above method, but I am not sure whether it will influence other modules in mxGraph.
mxGraphModel.prototype.createId = function(cell)
{
var id = myUtils.getUUID() //a method to return an UUID
return this.prefix + id + this.postfix;
};
That's fine, as long as the generated numbers are unique. What the actual values are doesn't matter.
Overriding the prototype is also fine if your intent is to do it for all mxGraphModel instances.

JQuery: How to cache DOM?

I used Firefug to profile my web application and found that the following function is called, and needs to be called, literally hundreds of times per user visit. So I want to optimize it since Firebug says it uses the most resources/times.
function highlightChildDiv(parentDiv) {
/* find the closest (hlisting) home listing to the middle of the scrollwindow & highlight */
var scrollElemPos = parentDiv.offset();
var highlightDiv = $(document.elementFromPoint(
scrollElemPos.left + parentDiv.width() / 2,
scrollElemPos.top + parentDiv.height() / 2)
).closest('#parentDiv div.childClass');
if (highlightDiv.hasClass("HighlightRow")) {
return; // if the div is already highlighted, return
} else {
$('#parentDiv div.childClass').removeClass("HighlightRow");
highlightDiv.addClass('HighlightRow');
}
}
Seems to me that one of the most un-optimized statements is .closest('#parentDiv div.childClass');, but I'm sure there is other things to improve.
Question: Does anyone have any JQuery performance tips on how I can optimize the code above given that this function is run literally hundreds of times per user visit.
First thought, eliminate the dead statement in the if clause.
if (!highlightDiv.hasClass("HighlightRow")) {
$('#parentDiv div.childClass').removeClass("HighlightRow");
highlightDiv.addClass('HighlightRow');
}
In the selector #parentDiv div.childClass, can you guarantee that div will be a direct descendent of #parentDiv? In which case:
.closest('#parentDiv>div.childClass');
and
$('#parentDiv>div.childClass')
You already have parentDiv. I'm guessing this is a DOM object, so you may be able to do the following:
$(parentDiv).children("div.childClass")
Just hide the DIV that is currently highlighted:
$('#parentDiv div.HighlightRow').removeClass("HighlightRow");
My guess is this is the most unoptimized line:
$('#parentDiv div.childClass').removeClass("HighlightRow");
You should profile it to make sure (create a date object outside the call and output the getTime() value before and after each call).
Here you are asking jQuery to iterate over all DOM elements that match that selector and remove the class. If there are 1000 rows, jQuery will need to interogate each one to see if it needs to remove a class. Ugh. Here it is with that lookup removed:
// namespace scoped cache
var Hash_$_Cache = {
$parentDiv : $('#parentDiv'),
$tgt_row : $([]) // empty jq object to start
};
// find the closest (hlisting) home listing to the middle of
// the scrollwindow and highlight
//
var highlightChildDiv = function (parentDiv){
var
scrollElemPos = parentDiv.offset(),
$tgt_row
;
$tgt_row = $(document.elementFromPoint(
scrollElemPos.left + parentDiv.width() / 2,
scrollElemPos.top + parentDiv.height() / 2)
).closest('#parentDiv div.childClass')
;
// bail if row is already highlighted
if ($tgt_row.hasClass('HighlightRow')){ return; }
Hash_$_Cache.$tgt_row.removeClass('HighlightRow');
$tgt_row.addClass('HighlightRow');
// save highlighted row for later
Hash_$_Cache.$tgt_row = $tgt_row; // store new row in cache
};
Hope that helps!
I prefer to use the following methodology:
https://gist.github.com/3841424#file-domcache-js
Or, you may replace the DOM object with a method in this implementation:
var myNS = {
myEventHandler: function(event){
this.DOM.$el.doSomething();
},
cacheDOM: function(){
return {
$el: $("#matrix")
};
},
initialize: function(){
this.DOM = this.cacheDOM();
}
};

Categories

Resources