Cannot retrieve parent id on child v-for in Edge - javascript

I have a form which contains a parent element and a child element, in every browser I can retrieve this value but in MS Edge I am unable to get the key from the parent element. Is anyone able to shed light on this issue?
<div v-for="(levelKey, level) in levels">
#{{ level.name }}
<div v-for="(currencyKey, currency) in currencies">
<input type="text" name="levels[#{{ level.id }}][currency.id]" v-model="...">
</div>
</div>

You can write your type attribute as a bound attribute using the :type syntax. See: https://vuejs.org/guide/syntax.html
Then you don't need the moustache braces (#{{ ... }}) when you're already inside an expression. You can just write:
<input :name="levels[level.id][currency.id]" v-model="...">
or even simpler (since you're already looping through levels):
<input :name="level[currency.id]" v-model="...">
EDIT
I created a JSFiddle with some mock data (probably not exactly the same as yours, though) and tried it in MS Edge. It worked fine:
Maybe you forgot to copy a part of the code?

Related

Angular 2 - trackBy function, what does it really do?

I was under the impression that trackBy function is used only when trying to optimize the performance of *ngFor, so that if something changes, the DOM doesn't have to be rebuild.
However, recently, I came across a situation when trackBy actually fixed a wrong behavior.
Take this for example: https://plnkr.co/edit/nRgdwoiKAMpsbmWaoMoj?p=preview
Focus on Hobbies section, especially HTML:
<div>
<h2>Hobbies</h2>
<div *ngFor="let h of user.hobbies; trackBy:customTrackBy; let i = index">
#{{i}} - {{h | json}}<br />
<input [(ngModel)]="h.name" name="hobby_name_{{i}}" /> <br /><br />
<select [(ngModel)]="h.type_id" name="type_{{i}}">
<option *ngFor="let t of types" [value]="t.id">{{t.type}}</option>
</select>
<br />
<br />
<button class="btn btn-warn" (click)="remove(i)">Remove</button>
<br /><br />
</div>
</div>
I had to explicitly define this part: trackBy:customTrackBy in the first *ngFor. If trackBy is removed, and the following steps are performed:
remove the first item
add a new item
In this case, the inputs of the first item get replaced with the content of the second item (both fields have the same content), however, the values in the model are correct.
trackBy solves this issue, but why?
I would really appreciate any kind of explanation. If this is not the right place to ask this kind of questions please redirect me to the correct one. Thanks.
update
Here's an example of the wrong behavior: https://plnkr.co/edit/u8YajKfHcPiVqY0WcJt7?p=preview remove the first item (cycling) and add a new item (add button) and see how both values get the same default value (BF will get replaced by "default value" even though the model stays correct).
*ngFor by default tracks items by object identity.
If you have primitive values like an array of strings, and use them in
<div *ngFor="let item of items; let i=index">
<input [(ngModel)]="item" name="item{{i}}">
</div>
and you edit one item, then *ngFor gets in trouble, because the identity of the edited item has changed.
With ngForTrackBy you can tell *ngFor to track the item by index, then above code will work fine when you edit fields.
Another use case is when you want *ngFor to track items by some custom object id property instead of the object identity.

Angular2 repeating selectors

I am doing something like this, where I am declaring selectors on the fly.
<div ngFor="let x of y;let i = index;">
<input *ngIf="i === 0" #selector0 type="number" value="{{item.value}}">
<input *ngIf="i === 1" #selector1 type="number" value="{{item.value}}">
</div>
Is there a way to do it like below, where I don't need to repeat myself?
<input #selector{{i}} type="number" value="{{item.value}}">
<button (click)="submit(selector0)">
I'm not looking for an alternative way to do it, just wondering if dynamic selectors are possible.
So we start here, where Angular defines these as a "Template Reference Variable":
https://angular.io/docs/ts/latest/guide/template-syntax.html#!#ref-vars
Okay, so let's try to find the source for that.
https://github.com/angular/angular/blob/master/modules/%40angular/compiler/src/template_parser/template_parser.ts#L34
https://github.com/angular/angular/blob/master/modules/%40angular/compiler/src/template_parser/template_parser.ts#L430
So we're trying to parse out the element... lets see how it defines that:
https://github.com/angular/angular/blob/master/modules/%40angular/compiler/src/template_parser/template_parser.ts#L16
I'm going to put a breakpoint and see what's up.
EDIT:
I put a breakpoint in the "_parseAttr" function to see what it sees when it looks at the template reference:
Here is the call to find the binding:
var hasBinding = _this._parseAttr(isTemplateElement, attr, matchableAttrs, elementOrDirectiveProps, animationProps, events, elementOrDirectiveRefs, elementVars);
And what the debugger outputs for the attribute name:
attr = Attribute {name: "#testerno{{check}}", value: "", sourceSpan: ParseSourceSpan, valueSpan: undefined}
So it looks like the attribute name name: "#testerno{{check}}" is not parsed to see if {{check}} is an angular variable, it just interprets that as part of the string.
Therefore, you cannot do what you put above. It thinks the reference name is "#testerno{{check}}" in this case.
Or, in your case, selector{{i}}.
Note that this makes sense because the "#" is used at the compiler level and is not present in your output html, so it would have no way of dynamically creating that reference.
Assign it to a data attribute, then you can use javascript's querySelector.
<input attr.input="{{i}}" type="number" value="{{item.value}}">

Do HTML input tags require an id or name?

I have a riot tag which contains a loop, shown below. This loop is inside another riot loop (maybe important?). After upgrading to riot version 2.3.0, the page become slow and unresponsive. The release notes stated riot loops were slower but more reliable.
I found that when I remove the ids from the input tags the page was again responsive. With no id on the inputs I thought I would re-write the onclick methods to identify which node was clicked some other way.
This didn't work as it appears my onclick methods aren't being registered. So my question: Is it illegal to have an input with no id or name? or is it likely I am doing something else wrong?
<div class="card-action">
<div each={field in obj.fields} class="col s6" no-reorder>
<a>{ field.label }</a>
<form action='#'>
<input type="radio" id="always-{field.id}" checked={ parent.currentDisplayAlways[field.name] } onclick={ parent.onInterestingFieldCheckboxClicked }>
<label>Always</label>
<input type="radio" id="conditional-{field.id}" checked={ parent.currentDisplayConditional[field.name] } onclick={ parent.onInterestingFieldCheckboxClicked }>
<label>Conditional</label>
<input type="radio" id="never-{field.id}" checked={ parent.currentDisplayNever[field.name] } onclick={ parent.onInterestingFieldCheckboxClicked }>
<label>Never</label>
</form>
</div>
</div>
I think you can bind method and add your ID or object in the method. You can use event if you want to find clicked item.
It is definitely legal to have an HTML input without a id or name attribute. To identify which node was clicked without an id in Javascript, you could pass the function that you want to call the this keyword, which is pretty much the entire DOM Object for that element as would have been retrieved by document.getElementById(). So, the function would look like so:
function firedAfterClicked(el) {
alert(el.checked); //Whatever you want it to do
}
And an input would look like so:
<input type="radio" checked={ parent.currentDisplayNever[field.name] } onclick="firedAfterClick(this)">
That code calls the firedAfterClick function whenever it is clicked, and passes it the input as a DOM element, courtesy to the this keyword.
However, I have a feeling that the true problem is something else to do with your Riot code. Taking out the id attributes seems like more of a temporary workaround than a real solution to me.

Angular directive inserts wrong DOM node

I have an app with many forms. Each field has several HTML elements, so I thought I could extract some directives (one per type of field) to keep my forms tidy.
I've created a sample app to demonstrate the problem, but I'm getting inconsistent behavior. In the sample app, a <link /> element replaces the <input />. In my real app, <input /> just gets removed from the DOM completely. I feel like this should be easy; why doesn't it work?
To answer your stated question, it's because you told it to, with ng-transclude. That replaces the contents of the tag with the original element, which I don't think you wanted; you probably wanted the original contents to be transcluded as the label instead.
This is probably what you're looking for:
<div class="form-group" >
<label for="{{htmlId}}" ng-transclude></label>
<input id="{{htmlId}}" class="form-control" type="text" ng-model="model" />
<span ng-repeat="error in errors">{{error}}</span>
</div>
I've moved the tranclusion into the label. While this works, I would also recommend the style of actually passing a label attribute, rather than transclude it, just for the sake of having a consistent API and simpler code; it's functionally equivalent, though, so don't let me bully you.
Also, you've got a few errors in your .js as well. First, you want to use = in your scope instead of &
scope: {
model: '=',
errors: '='
},
& is used to pass methods, while = is used for objects (this is a simplification). Since your model and errors are objects, you'll want to use = instead.
Finally, in your example, your html template and your directive's template don't have the same name... you've got an extra 's' in your .js, but that's probably just in the plunker and not your real app.

How to unlock a jquery ui check button when content is replaced with Backbone.js?

I have a web application which replaces content. This content has jquery ui check buttons. When I replace the content if a button already exists then don't add it again:
if(!$('label[for=checkWeekM]').hasClass('ui-button'))
$('.checkWeek').button();
If I push the button (its state is checked) and if I replace the content, the button starts locked until the same content is replaced again.
I use Backbone.js to replace the content
jsfiddle
How can I unlock the check button?
You are duplicating id attributes and that leads to bad HTML, bad HTML leads to frustration, frustration leads to anger, etc.
You have this in your template that you have hidden inside a <div>:
<input type="checkbox" class="checkWeek" id="checkWeekM" />
<label for="checkWeekM">L</label>
Then you insert that same HTML into your .content-central. Now you have two elements in your page with the same id attribute and two <label> elements pointing to them. When you add the jQuery-UI button wrapper, you end up with a slightly modified version of your <label> as the visible element for your checkbox; but, that <label> will be associated with two DOM elements through the for attribute and everything falls apart.
The solution is to stop using a <div> to store your templates. If you use a <script> instead, the browser won't parse the content as HTML and you won't have duplicate id attributes. Something like this:
<script id="template-central-home" type="text/x-template">
<div data-template-name="">
<input type="checkbox" class="checkWeek" id="checkWeekM" />
<label for="checkWeekM">L</label>
</div>
</script>
and then this to access the HTML:
content.view = new ContentView({
model: content,
template: $('#template-' + template_name).html()
});
Demo: http://jsfiddle.net/ambiguous/qffsm/
There are two quick lessons here:
Having valid HTML is quite important.
Don't store templates in hidden <div>s, store them in <script>s with a type attribute other than text/html so that browser won't try to interpret them as HTML.
I took a detailed look at your fiddle after you mentioned this problem. The solution I suggested here was more like a quick fix.
If you want to follow the right thing to avoid long term problems and side effects you should consider what is mentioned here. This way your problem is solved and there are no other bugs.

Categories

Resources