Build templated directive in AngularJS - angularjs-directive

I have blocks of HTML like this that repeat tons of time in my code:
<div>
<label for="producer">Producer:</label>
<select id="producer" ng-model="producer" ng-options="producer.name for producer in producers">
<option value="">-- Choose Producer --</option>
</select>
</div>
So I want to make a directive (??) where I could instead do this:
<gsBoundSelect gsLabel="Producer:" gsDefaultOption="-- Choose Producer --"
ng-model="producer"
ng-options="producer.name for producer in producers" />
The for/id fields could just be a random generated string.
I've been reading up on directives but I can't quite figure out exactly how to do this so that I can pass in parameters like this. The examples I've seen all want a bound scope variable passed in vs an attribute.
It seems like I need both a link function and a template, but I'm confused how to do that. Thanks.

Found enough data through various books to get something working. Not sure if it's the best way, but it definitely works:
module.directive('gsBoundSelect', function ($compile) {
function generateUUID() {
...
}
return {
restrict: 'E',
link: function (scope, element, attrs) {
var lblId = generateUUID();
var content = [
'<div>',
' <label for="' + lblId + '">' + attrs.gsLabel + '</label>',
' <select id="' + lblId + '" ng-model="' + attrs.ngModel + '" ng-options="' + attrs.ngOptions + '">',
' <option value="">-- ' + attrs.gsDefaultOption + ' --</option>',
' </select>',
'</div>'].join('');
// We need to transform the content into a jqLite object
var jqLiteElem = angular.element(content);
$compile(jqLiteElem)(scope);
element.replaceWith(jqLiteElem);
}
};
});
As a side-note...I discovered the element directives added must be closed with a full tag, not the shorter syntax like I showed in my example. So the above works with this HTML:
<gsBoundSelect gsLabel="Producer:" gsDefaultOption="-- Choose Producer --"
ng-model="producer"
ng-options="producer.name for producer in producers">
</gsBoundSelect>

Related

capture selected item value from a select drop down list created from a text file using jquery

I have a text file that contains a few simple words like: make, this, work.
I want to be able to load the text file and create a dynamic select drop down list from it. When the user clicks submit, it prints out the value of selected item.
Below is the code, I use handle bar to render the page to users. When the user clicks on the submit button, it goes to index/display to see what they selected.
Instead of printing out the actual value of selected options, it prints out index of the selected option, not the value.
<form method="post" action="index/display" id = "first" name="first">
<fieldset>
<div style="display: inline-block; margin-left:10px ">
<legend>Selecting items from text file</legend>
<script type="text/javascript" src="js/jquery.js"></script>
<script>
$.get("js/pytxt.txt",
function(data) {
/*alert( "Data Loaded: " );*/
var options = data.split(','),
$select = $('select#value');
for (var i = 0; i < options.length; i++) {
$select.append('<option value="' + i + '">' + options[i] + '</option>"');
console.log ($select)};
});
</script>
<p>
<label></label>
<select id = "value" name="first">
<option selected value="base">Please Select</option>
</select>
</p>
</div>
<p>
<input type="submit">
</p>
</fieldset>
This is the post function:
app.post('/index/display', (req, res) => {
res.status(200).send('POST works!' + req.body.first);
});
Please replace:
$select.append('<option value="' + i + '">' + options[i] + '</option>"');
With this line:
$select.append('<option value="' + options[i] + '">' + options[i] + '</option>"');
This should fix your problem.
You can simplify this a bit doing:
options.forEach(v => $select.append( new Option(v, v)))
Demo:
let options = 'one,two,three,four'.split(','), $select = $('#value');
options.forEach(v => $select.append( new Option(v, v)))
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<select id="value"></select>

Angular 6 - bind HTML created after compilation to click event

Im adding HTML elements at run-time when the user clicks a button.
I do this by setting the inner html of a div to a built up string then using DOMSanitizer.
Visually this look fine but the click events in the new HTML are not bound so nothing works, I guess because the HTML is generated after compilation.
Here is the code called when the user clicks to add a new component (it get populated with the correct data), can anyone suggest how I should hook it up to the click event in the delete image?
html on the page:
<div class="col-sm-9" >
<div [innerHtml]="contentHtml"></div>
</div>
code:
async AddText(contentText: string) {
this.htmlToAdd = this.htmlToAdd + ( '<br> <div class="card text-left">' +
'<div class="card-header text-secondary">Attraction Text' +
'<img align="right" class="image-hover pull-right table-header-padding" src="assets/images/LockLineIcon.png" />' +
'<img #delete class="image-hover float-right text-danger icon-pad draft-icon-indent" src="assets/images/DeleteIcon.png" (click)="this.delete(0)"/>' +
'</div>' +
'<div class="card-body" >' +
'<textarea id="text" name="text" type="text" class="form-control" required maxlength="2048" >' + contentText + '</textarea>' +
'</div>' +
'<div class="card-footer">' +
'<img align="right" class="pull-right table-header-padding" src="assets/images/DragUpDownIcon.png" />' +
'</div>' +
'</div>');
this.contentHtml = this.sanitizer.bypassSecurityTrustHtml(this.htmlToAdd);
}
Your DOM may be sanitized, but it's not part of Angular's DOM. If you want Angular to see the DOM, you have to let Angular make the DOM - and that means dynamic components. Something like this would work:
#Component({
selector: 'my-component',
template: `<h2>Stuff bellow will get dynamically created and injected<h2>
<div #vc></div>`
})
export class MyComponent {
#ViewChild('vc', {read: ViewContainerRef}) vc: ViewContainerRef;
private cmpRef: ComponentRef<any>;
constructor(private compiler: Compiler,
private injector: Injector,
private moduleRef: NgModuleRef<any>,
private backendService: backendService,
) {}
ngAfterViewInit() {
// Here, get your HTML from wherever.
this.someService.getThatAsyncHTMLOfYours.subscribe(rawHTML => this.createComponentFromRaw(rawHTML));
}
// Here we create the component.
private createComponentFromRaw(template: string) {
// Let's say your template looks like `<h2><some-component [data]="data"></some-component>`
// As you see, it has an (existing) angular component `some-component` and it injects it [data]
// Now we create a new component. It has that template, and we can even give it data.
const tmpCmp = Component({ template, styles })(class {
// the class is anonymous. But it's a quite regular angular class. You could add #Inputs,
// #Outputs, inject stuff etc.
data: { some: 'data'};
ngOnInit() {
/**
* HERE'S YOUR STUFF
* do stuff here in the dynamic component, like binding to locally available variables and services.
*/
}
});

Extract name from input inside of string in smarty

I was wondering if there is a possibility to extract attributes from a string in Smarty.
Sample:
{$mySmartyArray}
//This array contains
//Array( 0 => "<input name='aaa' />",
// 1 => "<input value='' name='bbb' placeholder='' />",
// 2 => "<input placeholder='foobar' name='ccc' />"
// );
What I want to achieve is something like:
<select name="{$mySmartyArray[0]:attr[name]}">
Of course, I know this looks kind of crap, but I'm looking for some kind of selector.
Or am I supposed to do this with a dirty strpos search ?
Or is a regular expression a possibility?
The task is:
PHP calls some functions and creates the smarty stuff. Now I want to replace the inputs in the array with some select-options.
I'm about to create a smarty plugin to do something like:
<select name="{preg_match value=$mySmartyArray[0] pattern='myRegExHere'}">
<option>...</option>
</select>
Which brings me to my next question: What would be the regex for selecting this?
I added a Plugin to solve my problem:
function smarty_function_preg_match($params, &$smarty)
{
if (!empty($params['pattern']) && !empty($params['subject'])) {
$subject = $params['subject'];
$pattern = "~{$params['pattern']}~";
preg_match($pattern, $subject, $match);
return $match[1];
}
}
The usage is now
{preg_match pattern='name="(.*?)"' subject=$new_item_data.content}
In my case, this returns the name value:
<select name="{preg_match pattern='name="(.*?)"' subject=$new_item_data.content}">
<option>aaa</option>
<option>bbb</option>
</select>

Select2 acts very different with Uncaught query function not defined for Select2 <select2-id>

I load values for select2 like the following way.
Declare the Type
var AdjustmentType = Backbone.Model.extend({
url : Hexgen.getContextPath("/referencedata/adjustmenttype")
});
create instance for the Type
var adjustmentTypes = new AdjustmentType();
load the values to select2 box
adjustmentTypes.fetch({
success : function() {
for(var count in adjustmentTypes.attributes) {
$("#adjustment-type").append("<option>" + adjustmentTypes.attributes[count] + "</option>");
}
}
});
$("#adjustment-type").select2({
placeholder: "Select Adjustment Type",
allowClear: true
});
My HTML Code
<div class="span4">
<div>ADJUSTMENT TYPE</div>
<select id="adjustment-type" tabindex="5" style="width:200px;">
<option value=""></option>
</select>
</div>
when i load this for the first it is not giving any exception but if i Refresh or navigate to different URL i get the following exception:
Uncaught query function not defined for Select2 adjustment-type
"Query" refers to the list by which to check your search terms against. You need to make sure that your data property is a proper array of objects (ie. your options elements).

Form Element not writeable but works with iframe

i created a form element like that:
<form id="TextForm1" name="TextForm1">
<input type="text" id="Text1" name="Text1" value="" placeholder="" />
</form>
But it isn´t working in my .html site. I can´t type in something.. But if i embed it with an iframe it works perfectly.. I am using a scrolling script "iscroll" in my content area. But i can´t figure out why it isn´t working with it.
Does anyone have an idea? Thanks
You are using jQuery so you can use click event like:
Check Out The Working Demo
$(yourElement).click(function()
{
// your code
});
I changed two functions of your code to this and removed the onclick event from the inputs:
JavaScript:
$('#buttonCm').click(function(){
var cmEingabe = document.getElementById("cm");
var cm = cmEingabe.value;
var cmNeu = cm - 3;
$('#Liste').append('<br/>' + '<br/>' + '-' + ' '+ 'Bauteil passend zu ' + cmNeu +'cm' + ' ' +'Breite');
$('#Form1').fadeOut(700);
$('#Form2').delay(700).fadeIn(700);
});
$('#buttonCm2').click(function(){
var cmEingabe2 = document.getElementById("cm2");
var cm2 = cmEingabe2.value;
$('#Liste').append('<br/>' + '<br/>' + '-' + ' '+ 'Bauteil passend zu ' + cm2 +'cm' + ' ' +'Höhe');
$('#Form3').fadeOut(700);
$('#Liste').delay(700).fadeIn(700);
});
HTML:
<input type="button" id="buttonCm" name="buttonCm" value="auswählen" />
<input type="button" id="buttonCm2" name="buttonCm2" value="auswählen" />
I hope this might help you. But I could not find the script in your code to check how you had bind the iScroll plugin. Because iScroll it self prevent some events. But most probably if any form fields not responding after you bind iScroll means this is the solution which I used to overcome.
input fields not responding after added 'iscroll'-PhoneGap