alpinejs : limitations on usage of x-on directive - javascript

It seems to me like the x-on directive does not work without the presence of an x-data directive on a parent element.
For example, the below does not work
<button
x-on:click='console.log("hello")'>
left
</button>
It needs to be converted as following for it to work
<div x-data="{}">
<button
x-on:click='console.log("hello")'>
left
</button>
</div>
If I am understanding it correctly and an x-data directive is necessary, why would it be that way?

The x-data directive is required because of the main philosophy of Alpine.js framework.
With a full SPA (single page application) framework, like Vue.js, the main index.html file usually has only a single empty element inside <body>, like <div id="app"></div>. Then we mount our Vue.js application to the #main element and Vue.js takes over the entire frontend. After that by default everything is assumed to be a Vue.js component, like <MyComponent :some-data="42"></MyComponent>, so we don't have to mark them in any other way.
However, Alpine.js follows a different path. It is not intended to be a full SPA framework, like Vue.js. Its main purpose is to "enhance" frontend markup code generated by a backend framework like Django/Laravel/etc (the author of Alpine.js, Caleb Porzio, is the author of Laravel Livewire). So here by default a <button> element is assumed to be a normal button, not an Alpine.js component, therefore Alpine.js does not scan it for Alpine.js specific attributes, like x-on. We have to add the x-data attribute to an HTML element like <button> to mark it as an Alpine.js component. After that Alpine.js scans for directives as such, and takes over the handling of the marked element. This method works well with backend frameworks, where we usually only want to make some elements interactive on the frontend with Alpine.js, but any other logic is handled by the backend.
Nevertheless, if you want you can add an empty x-data attribute to the main <div> element in your markup, that makes Alpine.js work as an SPA framework, so it will scan every element for Alpine.js specific attributes. That's totally fine if you want to use Alpine.js this way. But usually we can define smaller, reusable components, so we put the x-data={} attribute to the specific element or to closest ancestor of the element.

Related

How to parse a html string to native angular template

Currently I'm rendering the html string using innerHtml property after bypassing the angular sanitizing mechanism this is working for rendering the contents. But not able to map the event handlers to a function in angular component.
E.g.the html string will contain a button like below
<button (click)="callme()">Click</button>
the callme function will be part of angular component file. I want this click event to be handled in angular function.
Is it possible to parse this string to html dom and handle the events in angular components.
Sample code which describes this scenario and using angular cdk Portals.
https://stackblitz.com/edit/angular-upaudh?file=src%2Fapp%2Fcdk-portal-overview-example.ts
There are 2 ways that you can implement it, it depends from what you want.
The easy way is to use innerHtml input like this:
HTML
<div [innerHTML]="htmlStr"></div>
TS
htmlStr: 'Hello';
If you want to create a dynamic template that will be translated to HTML at build time. Then you have to go with Portals.
PS: In your example (in the comments) you use [innerHtml] and try to bind it in a Portal. Again [innerHtml] will not be translated before runtime so your click event will not be in the same scope as your component. The thing that you ask is an open conversation in github: Issue. For now you can use the alternatives above to solve your case. You can use innerHtml, and then use renderer2 or native element reference to bind click events to your functions, after they have rendered on the view.

Is it possible to convert html homepage to a react component to render in Index.js Create-React-App

I have an existing templated website that i want to continue with react. I decided to use create-react-app for that, but i do not know how to move the html based template to the react application. What i am trying to do now is to find a way to create a functional component out of the html file and then pass it to the index.js file for rendering. What i don't know is if this will work. Any ideas on the best way to do this?
There have tiny changes with HTML and JSX. JSX use className instead of class and htmlFor instead of for as mentioned up there.
If you are using VS code editor, here are your steps to make things a bit easier:-
In Vs code, Download an extension name HTML to JSX.
open your raw HTML code with VS code.
Select all code you want to convert.
Right-click and see at the bottom of the list, you will see an option Convert HTML to JSX. Click it and you are done.
step:1
step:2
result
Yes it is, and JSX was designed to be very similar to HTML to allow just that sort of thing.
However, JSX does have a few differences from HTML, which you'll want to read about. For instance, certain HTML attributes "overlap" with JS keywords, so in JSX you should use (for instance) htmlFor instead of for, and className instead of class. Also every tag has to be closed (as in XHTML).
Once you get your initial HTML into your Javascript file, you'll then want to start breaking up the parts of that page into separate React components, so that you can focus on them (and their logic) in independent chunks.

Can we append angular material form fields within a div?

I have a div tag and I want to append the angular material form fields inside that div. The problem is it's not rendering that tags. Can we do this using any method?
enter image description here
The angular way is has an array of object, e,g.
data=[{placeholder:"Enter Name",label:"Name"},
{placeholder:"Enter surname",label:"Surname"}]
and make some like
<mat-card *ngFor="let item of data">
<div class="row">
{{item.label}}<input mat-input [placeholder]="item.placeholder">
</div>
</mat-card>
When you are using angular, never manipulate the DOM manually (via native DOM APIs or jQuery).
When you are using a component or a directive in an angular template (ie. the html of your component), that is not real html, that is transformed to javascript. So when the application is running, where you wrote <mat-car> in you template and you also see <mat-card> in the DOM, that was actually put there by the code generated by angular, but a lot other things also happened (ie. the mat-card component was initialised).
When you just put the components selector manually into the DOM, nothing will happen, because the component is not initialised. To make it work, you have to use the material components from another components' template. Further reading: https://angular.io/guide/architecture-components
Suggestion: don't even import jQuery into the project at all, that way you won't even be tempted to do this.

Add arbitrary Vue.js components to parent component

I'm using Vue.js to build ui for my html5 game. I have a case where I want to define ui-containers which essentially just group other ui-components and position them to somewhere on screen. So I could have something like this going on:
<ui-container>
<ui-component1></ui-component1>
<ui-component2></ui-component2>
<ui-component3></ui-component3>
</ui-container>
Where I need to add and remove those components dynamically based on data-model which represents the content of the container. The problem is that I'd like to keep ui-container generic, so that I can append any Vue-component to it without having information in template about which components there might be.
I googled and found this example which concerns injecting components dynamically: http://forum.vuejs.org/topic/349/injecting-components-to-the-dom
While the data-driven version in example was easy to make and understand, it uses v-for for tag and therefore requires one to know before hand the type of child-component.
So question is, how I can generalize that example to work with any component dynamically? Should my data-model have the type of component or tag name of it and then interpolate it in v-for? Or is there existing mechanism for this kind of requirement?
You can use special is attribute to dynamically set the type of a component. Here are the docs. The code will look somewhat like:
<div id="app">
<div v-for="component in components" :is="component.type" :value="component.value"></div>
</div>
Working fiddle to play with: Dynamic Vue.js components

Polymer elements within angular 2 component

I have a set of custom polymer elements, that I would like to use within an angular 2 application.
It seems like there's a problem concerning the content tag of the polymer element. The content of the element gets rendered at the wrong place within the polymer element, if the element is located within an angular 2 component.
Example:
The template of my polymer element "my-button" looks like this:
<template>
<button>
<content></content>
</button>
</template>
Use outside angular
When I use this element outside of my angular 2 component, I get the result that I expected:
Use:
<my-button>Foo</my-button>
Result:
<my-button>
<button>
Foo
</button>
<my-button>
Use within angular 2 component
When used within an angular 2 component, the content always gets rendered at the end of the elements template. Just like the content tag didn't exist.
Use:
<my-button>Foo</my-button>
Result:
<my-button>
<button>
</button>
"Foo"
<my-button>
Question
The problem might be, that polymer and angular 2 both use the content tag for transclution. So maybe things get a little messy when using both together.
I would love to use all of my polymer elements inside angular 2. So any ideas on how to fix this would be very much appreciated.
There are a few open issue about Angular2 combined with Polymer. For example Angular doesn't use Polymer.dom(el)... for manipulating a Polymer elements children. This is probably what breaks your components.
A workaround is to enable full shadow DOM and polyfills. See https://www.polymer-project.org/1.0/docs/devguide/settings.html
An issue I haven't found a solution yet is passing <template>s (like required for example for <iron-list>. Angular handles templates on its own and doesn't pass it to the Polymer element.
There is a ngNonBindable directive. I haven't tried it yet on the <template ngNonBindable> myself but it might work. I tried it seems that's only to ignore [prop]="field"/prop="{{field}} bindings.
Another issue is with <style is="custom-style">. They can only be added in the <head> element or within Polymer elements, but not to Angular components.
See also Two-way binding in Angular 2 with NgModel and mutating bound property?
Check out https://www.npmjs.com/package/#vaadin/angular2-polymer, which should resolve most issues in integrating Polymer elements to Angular 2.
User guide: https://github.com/vaadin/vaadin-core-elements/blob/master/docs/angular2.adoc
Tutorial (draft): https://github.com/vaadin/angular2-polymer/blob/d4581e8fd82841eea84ef40e16e262a12ee4b082/docs/tutorial.adoc
Better shady DOM support is waiting to be merged from a separate branch (should be merged and released within two weeks): https://github.com/vaadin/angular2-polymer/tree/feature/polymer-dom-adapter
It would be great if you could try it out and see if it works for you!
Eventually, the documentation will be published at https://vaadin.com/docs/

Categories

Resources