custom component binding in knockoutjs - javascript

I am trying to load custom components using knockoutjs.
Here is my HTML :
<div id="mainDiv"></div>
JS:
$("#mainDiv").append("<my-component-name></my-component-name>");
This appends <my-component-name></my-component-name> after div but does not bind my component to html.
If I use ko.applyBindings(); it throws error "Error: You cannot apply bindings multiple times to the same element."
I am not able to find whats wrong with bindings.

The view is updated, but the bindings are not. You need to do ko.applyBindings on any elements inserted in the HTML after the bindings are applied the first time. It's a lousy solution to apply components after applying bindings. And DON'T mix knockout with jQuery or js DOM manipulation, PLEEEASSE!

Here I got the solution:
var myComp = document.createElement("my-component-name");
$("#mainDiv").append(myComp);
ko.applyBindings({},myComp);
Ko.applyBinding was needed to bind my component in html.

Related

Automatic click element after all data loaded in Angular 2

I am trying to figure out how to automatic trigger a click event on certain element after all data are loaded.
the code is like this in html file:
<div *ngFor="let location of locations; let i = index;" class="location-wrapper" (click)="onSelect($event, i); $event.stopPropagation();">
<div class="location">{{ location }}</div>
</div>
the onSelect() method is doing some expansion of something that related to current location.
What I am trying to achieve is that I want the very first element of the *ngFor can be automatically clicked to show the things that related to it every time I get to this page.
Or maybe we can achieve it using other similar approach?
I have tried several ways to do this,
like putting some code in window.on('load', function() { // blablabla });
or using ngAfterViewInit() and ngAfterViewChecked(), both not work well.
You can do this in at least 2 ways. The first one would be old-fashioned javascript click(). The second would be just using component logic, just create an variable like selectedLocation which would hold current index or Object that is currently expanded. Don't forget to add initial value to it to make it after load page visible.
Javascript dispatchEvent (not Angular friendly solution)
Simply we just need to grab our item and use click() function. That's it. To grab an element we can use basic javascript method document.getElementById(elementId)" or with template variable.
<div
[id]="'location_' + i" <!-- For biding with document.getElementById -->
#locationPanel <!-- For biding with template variable -->
*ngFor="let location of locations; let i = index;" class="location-wrapper" (click)="onSelect($event, i); $event.stopPropagation();">
<div class="location">{{ location }}</div>
</div>
With Id it would look like document.getElementById("location_0").click() this gonna dispatch click event on element.
For template variable in your component you need to add
#ViewChildren locationPanel: QueryList<any>;
openFirstLocation() {
if (this.locationPanel && this.locationPanel.first)
this.locationPanel.first.nativeElement.click();
}
And in afterViewInit just call this.openFirstLocation();
Please note that it's not Angular friendly because Angular does not like when you interfere directly with DOM. However as long we don't change anything in structures then everything should be fine, but we should avoid manipulating dom with plain javascript.
Please note that too about using #ViewChild and document.* methods.
Use this API as the last resort when direct access to DOM is needed. Use templating and data-binding provided by Angular instead. Alternatively you can take a look at Renderer2 which provides API that can safely be used even when direct access to native elements is not supported.
Relying on direct DOM access creates tight coupling between your application and rendering layers which will make it impossible to separate the two and deploy your application into a web worker.
From Angular docs link

Render angular2 Component from javascript and get html in return

Is there a way to execute angular2 component from JavaScript and get generated HTML in return?
I would like to write a function in plain JavaScript/JQUERY which should execute angular2 component and returns generated HTML.
For example: something like
var html = executeAngular2ComponentAndReturnHtml('componentName');
Any help will be highly appreciated.
Thanks
You can use the innerHTML attribute to do that. Bind it to a property of your component class like this:
<div [innerHTML]="customHtml"> // note the casing of innerHTML.
</div>
In your Component code:
this.customHtml = executeAngular2ComponentAndReturnHtml('componentName');
Important: You may also want to mark your HTML as trusted so that Angular2's DOM sanitizer does not remove parts of it. For this, please see angular 2 html binding

ng-click not working when using append function

I am trying to call a function using ng-click when dynamical elements are created but with no success so far. Here is my code
$scope.myfunc = function(){
alert("anything")
}
var divtoappend=angular.element( document.querySelector('#slist'));
divtoappend.append("<button class = 'optv' ng-click='myfunc()'>" +mybutton+ "</button>");
...
No error is thrown and nothing happens on click
You have to compile DOM with $compile API, before injecting into DOM tree, like below.
divtoappend.append($compile("<button class = 'optv' ng-click='myfunc()'>" +mybutton+ "</button>")($scope));
By compiling DOM angular will put all HTML level bindings in $$watchers array of $scope to make sure UI is up to date on every digest cycle.
You need to compile the dynamically generated HTML so that it is under the scope of AngularJS.
Just compile inside append method like
divtoappend.append($compile("<button class = 'optv' ng-click='myfunc()'>" +mybutton+ "</button>")($scope));
Before this inject $compile in your controller.
I have created a plunkr see this plunkr link
You need to compile your DOM elements as follow using $compile
$compile(divtoappent)(scope);

Jquery Toggle on click of image

I am trying to understand how the jquery toggle works. I want to toggle to next anchor with class plr-anchor on click of image with class go_down. The data is populated using maps.
Jquery code:
$('.go_down').on('click',function(e){
#('.plr-anchor').next('.plr-anchor').toggle()});
}
Code snippet:
{data.map(function(categ) {
return <div>
<a className="plr-anchor" id={categ.short_name}></a>
<img src="/static/img/icon_up.png" className="go_down"/>
</div>}.bind(this)}
There seems to be a problem with the syntax on the Jquery call function. I am newbie with Jquery, any help will be great. Thanks in advance.
You have used # instead of $ inside click handler. Also you need to find exact plr-anchor which is before the clicked image. Right now you are toggling all plr-anchor.
For dynamic elements, use $(document).on(event, selector, function(){}); for binding click handlers. See below code
$(function(){
$(document).on('click','.go_down',function(e){
$(this).prev('.plr-anchor').toggle();
});
});
Your jQuery code has a "#" instead of a "$". By the way, React and jQuery don't always go together. The whole purpose of React is to use virtual dom and let React take care of dom updates. While jQuery is mostly about direct dom manipulation. What you are trying here will interfere with React because it won't expect the dom to change without the v-dom changing.
Ideally, you should be using event handlers and state in your component to toggle visibility.

Ember.js / Handlebars: views rendered using {{view}} helper not binding attributes

I have a mysterious issue with Ember/Handlebars views. I am attempting to implement very simple data binding in a Handlebars view. This works correctly when render my view by doing:
Ember.Views.NavView.create().append()
But the bound attribute isn't shown when I attempt to render another instance of the same view using the {{view}} helper, like so:
<script type="text/x-handlebars">
{{view App.Views.NavView}}
</script>
In the first case the attributes (hardcoded on the View for this test-case) are shown correctly. In the second case I get "metamorph-0-start" and "metamorph-0-end" tags, but the value itself is not rendered.
I have set up a JSFiddle (http://jsfiddle.net/XUyht/2/) that illustrates the problem clearly.
You'll see that I have rendered the view twice: the first using the {{view}} helper and the second using append() - but the attribute "working" only shows in the latter case.
What's going on here?
I don't know why you need this kind of implementation of the template, but anyway, since the 1.0-pre, the default context of a view is either its controller, either its parent view. So in your case, if you replace tmp.foo with view.tmp.foo, this is working.
see http://jsfiddle.net/Sly7/amLfk/

Categories

Resources