Dynamically appending child nodes with Ionic CSS - javascript

I want to add styles from the Ionic CSS library to the HTML element created in Javascript. The purpose is because I'm pulling objects from my database and dynamically creating buttons for them. I can receive these items and add them to the page but I'm unable to use format it properly. This is a basic HTML example of what I want to replicate in JavaScript.
<ion-list id="list" (click)=add()>
<button ion-item>
<ion-icon name="ios-add" item-start></ion-icon>
Add
</button>
</ion-list>
To produce this button:
This is what I have in Javascript.
add() {
var listItem = document.getElementById("list");
var listButton = document.createElement('button');
listButton.setAttribute("class","ion-item");
listButton.setAttribute("id", id+"1");
var icon = document.createElement("ion-icon");
icon.setAttribute("name","ios-add");
let text = document.createTextNode("Add");
listButton.appendChild(text);
listButton.appendChild(icon);
listItem.appendChild(listButton);
}
This is what the above[code produces:
How can I use JavaScript to manipulate the DOM while retaining Ionic formatting?
Using: Node 8.3.0, Angular 4, Ionic 3.

I have a similar problem, what I am pushing the objects to an array every time I clicked on an object, I would push it to the array created in the front-end and display the array of objects in a separate component, that way I can style only the selected items.
The other option would be to copy the whole data objects and add props of boolean type like "added" or "in_playlist" but there may be a lot of data therefore I would suggest the first solution.

Related

Is there a way to run this script in a sequence?

For context I've made a script to assign a localstorage item based on what the user selects, this item may contain "S10" but could also contain many other values, for this example the user has selected "S10"
This has now stored into localstorage.
I have created this script that I have placed in each of the product grid includes, so this script will load multiple times for each product:
window.onload = function() {
const string = localStorage.getItem('MyfitmentList', JSON.stringify(myfitment) );
const attr = {{ product.metafields['fitment']['fitment'] | json }};
document.getElementById("fitment").innerHTML = (`${string.includes(attr) ? '✔' : 'not a fit' }`);
}
Each product grid also features this container <div id="fitment"></div>
The script above loads individually for each product grid card and has it's own seperate values for "attr". If "attr" doesn't contain "S10" (which the user previously selected) then it should show "not a fit", but if the product does contain "S10" then it should show the tick.
The problem I'm having is that this only works for the first script, on the first <div id="fitment"></div> container. I can see that each individual script has a different "attr" value which is good, but I don't know why only the first container is populated.
Each script should run individually and populate the "fitment" container within it's own product card. I'm a bit at a loss as to how to do it.
Also this is on Shopify - Someone below has recommended using a single script with a loop, but in that case how would I retrieve a unique "attr" value each time the script loops? this would still leave the question of how to populate each fitment container with the correct message for each product.
Any help would be really appreciated!

ReactJs - Add open and closing tag without syntax error

I have to generate a form from a JSON with materialize.
Generate the form components is not a problem but Im not able to create <span class="row"> to separate form inputs.
In my form component render method, Im iterating the json data and put every component (textfield, dropdown etc...) in an array and then return it.
render()
{
return <span className="row"> { this.buildForm() } </span>
}
This works greats but every input are printed inside a single row so I got problem when materialize has to manage input cols.
So I need to create dynamically the row span.
In my json I put a specific attributes call "rowstart" and "rowend" for every input field so I know if that input will start a new row or will close one.
For example if I have two input with cols = 6, the first one will have rowstart=true and the second one will have rowend=false
The problem came in render. I cant put an open or a close tag in the render.
if (attributes.rowstart)
{
formRender.push(<span className="row">);
}
switch(attributes['type'])
{
case 'string': formRender.push(<TextField .... />); break;
[...]
}
if (attributes.rowend)
{
formRender.push(</span>);
}
The render doesn't allow open/close tag because its now sure what happens in the next iteration so it can't say if the open tag will be really close.
Is there a way to solve it?
Searching on StackOverlow i found this post but its different from what I need. stack post
I suggest that you make rows a top level array elements and make every other inputs as children of rows
```
if (attributes.rowstart && attributes.children.length)
{
let row = (<span className="row">{attributes.children.map((input)=> <Input key={input.name} /> )}</span>);
formRender.push(row);
}
```

Unchecking all the rows in px-data-table

I am using px-data-table in an Angular2 application.
The data-table is used as follows:
<px-data-table #myTableRef [tableData]='tableDetails' language="en" (px-row-click)="selectedChanged($event)" (px-select-all-click)="selectAll($event)" sortable selectable show-column-chooser>
<px-data-table-column *ngFor="let header of headers" type="html" name="{{header.value}}" label="{{header.label}}" [disableHide]="header.disableHide" [hide]="!header.disableHide">
</px-data-table-column>
</px-data-table>
The user selects more than one rows. So selectedChanged($event) is fired and multiple rows are selected. Now I'd like the selected rows to be unchecked from code not via user interaction. I went with the following approaches (which did not work):
Fire event 'px-select-all-click' from Angular by:
this.myTableRef.nativeElement.fire('px-select-all-click')
this.myTableRef.nativeElement.fire('px-select-all-click', this.myTableRef.nativeElement.selectedRows)
// also did a ChangeDetectorRef.detectChanges() after injection but it did not work.
Select the checkbox with id 'selectAllCheckbox' from Angular by:
this.myTableRef.nativeElement.shadowRoot.querySelector('selectAllCheckBox')
this.myTableRef.nativeElement.querySelector('selectAllCheckbox')
//returns null in both cases so I can't do a .click() on it
Empty the selectedRows attribute:
this.myTableRef.nativeElement.selectedRows = [];
All three methods don't work.
I was looking inside the aha-table.html imported inside the px-data-table.html and found a convenient method: _setAllRows(e) which unselects all the rows with _setAllRows(false). If only this was exposed or I could call this from Angular, I'd have my solution to the problem: unchecking the selected rows.
Any solutions would be helpful.
After noticing that the _setAllRows(e) is a method of aha-table which is a component nested under px-data-table component, accessing the method is easy according to the Polymer documentation for Local DOM API.
let tableRef = this.myTableRef.nativeElement;
tableRef.$$('aha-table')._setAllRows(false);
Basically $$('selector') is the Polymer shorthand for dynamically created nodes. If I get the reference for the aha-table node, I can call its methods.

Accessing dynamic element id's in AngularJS

I am working with an app that has an ng-repeat that populates a navigation sidebar with a list of items from a Mongo DB. The ng-repeat also populates a series of option buttons for each item. A couple of these option buttons share a dynamic id for each iteration in the ng-repeat. What should be happening here is when I click on one of these buttons, it would change the button 'text' and display some additional options under the menu item and toggle back when clicked again.
Here is my code for these buttons:
<span>
<button ng-hide="highlightItem()" ng-click="showTopic()" ng-attr-id="{{ 'category' + subject._id }}" class="add-button"><i class="fa fa-chevron-down"></i></button>
<button ng-click="hideTopic()" ng-show="highlightItem()" ng-attr-id="{{ 'category' + subject._id }}" class="add-button"><i class="fa fa-chevron-up"></i></button>
</span>
The issue that I am having is that I cannot seem to figure out how to access that dynamic id in my controller. I have code in place that will change the button between the ng-show and ng-hide, but it does it for all iterations of ng-repeat.
This is currently how I am attempting to access the dynamic id. I am not getting any errors, but when I try to use this in my function it doesn't work.
$scope.subjectList = subjects.get({});
var topicButton = document.getElementById('topic' + $scope.subjectList._id);
I have also tried
var topicButton = document.getElementById('topic' + $scope.subject._id);
What is the best way to access the dynamic id in Angular/Javascript? I do not want to use jQuery with this if at all possible.
First and foremost, never manipulate the DOM within an angular controller! It is bad practice. Also, it is bad practice to evaluate methods in ngShow/ngHide.
If I understand you correctly, you're trying to get the subject_id for some reason when the button is clicked. Why can't you just pass back either the id or the entire subject to your method? Then your html would look something like this:
<span>
<button ngClick="toggleTopic(subject)" class="add-button">
<i class="fa" ng-class="{'fa-caret-down': subject.hidden, 'fa-caret-up': !subject.hidden}"></i>
</button>
</span>
Then in your controller you could write something like this:
$scope.toggleTopic = function(subject) {
subject.hidden = !subject.hidden;
};
Using the hidden attribute of your subjects, you can now show or hide elements of your dropdown with ngShow/ngHide like so:
<p ng-bind="subject.descripton" ng-hide="subject.hidden"></p>
This way, you don't have to search the DOM for elements at all.

jQuery Cloned django-selectable Autocomplete Dropdowns Not Working

As the title states, I have a django-selectable autocomplete form field on my page, that I am trying to clone dynamically after page load. The cloning part works, but the autocomplete fields do not function. I don't know the internals of django-selectable, and I'm still learning jQuery so I am lost as far as figuring out how to "fix" the autoselect functionality.
My general approach is this: I render the form widget using django template variable inside a div container, and I clone the div container.
HTML
<div class="autocomplete" id="autocomplete_{{ form.instance.id}}">{{form.autocomplete_dropdown}}</div>
jQuery
// This works, just the cloned form lacks "autocomplete" functionality.
var autocompleteArray = theDiv.find('.autocomplete');
var acClone = autocompleteArray.clone();
table.find(".column").append(acClone);
Based on SunnySydeUp's comments I made the following revisions:
jQuery
// Clone the div and all its contents
var acClone = autocompleteArray.clone(true, true);
// Get the children of the div
var acCloneChildrenArray = acClone.children();
// iterate through the children array, modify ids where they exist to make them unique
// e.g., unique id contained in idSuffix.
for (var i = 0; i < acCloneChildrenArray.length; i++) {
// if it has an id, make it unique
if (acCloneChildrenArray[i].getAttribute('id')) {
var ident = acCloneChildrenArray[i].getAttribute('id')
acCloneChildrenArray[i].setAttribute('id', ident+'_'+idSuffix);
};
};
Now the data and events are copied, but they are tied to the prototype/master dropdown. That is, clicking one of the cloned objects actually triggers the dropdown for the master. I guess the question comes down to how to attach the event handler dynamically to the new dropdowns?
Final working code (has a minor bug--duplicated dropdown button, but the autocomplete and dropdown functionality works, per SunnySydeUp's solution).
jQuery
// Clone the div
// We leave clone deepcopy flags at default==false
var acClone = autocompleteArray.clone();
// Get the children of the div
// You don't need to set unique id's on the children, it's irrelevant.
// Bind the new selectable fields to the event handlers.
window.bindSelectables('body');
I haven't used django-selectable before but I'm guessing it uses javascript/jQuery to make the autocomplete work. When you call clone, it doesn't clone the javascript for the dropdown. Try doing:
var acClone = autocompleteArray.clone(true);
Passing in true will make jQuery also copy the data and events on that input.
Clone documentation

Categories

Resources