Reactjs server side templates - javascript

I wonder is there a way to load a react component template from server?
When I worked with Vuejs or any other js-library I actually have to add code to a view and after it rendered by server javascript starts running and do the rest.
For instance, I can type something like this in a Symfony app to get localized string: {{ 'header.article_title'|trans }} and it were translated.
However, since templates are hardcoded into a reactjs-component I can not use php/symfony/twig functions anymore. So, I'm wondering if there a way to fetch template from a server like an AngularJS templateURL-option.

Finally get how to do what I need.
I've realized that it is possible to not have actual file by URL. So, if I need a /react/component/Article.js it could be a URL to an action.
So, I've created a new bundle, add a controller and use one action with view for a single react-component.
The skeleton code looks like this:
/**
* Class ComponentController
* #package ReactjsBundle\Controller
*
* #Route("/react/component")
*/
class ComponentController extends Controller
{
/**
* #Route("/Article.js")
*/
public function articleAction()
{
$resp = new Response();
$resp->headers->set('Content-Type', 'text/javascript');
return $this->render('ReactjsBundle:Component:article.html.twig', [], $resp);
}
}

Related

Custom methods on Model Laravel and Vue

I am currently trying to implement a bookmark feature in my laravel project and i am using this design.
The Bookmark table is a pivot for User and Post table, a many to many relationship
public function BookmarkPost(Request $request,$id)
{
$book = Auth::guard('api')->user()->bookmarks()->attach($id);
return response()->json( $book);
}
/**
* Unfavorite a particular post
*
* #param Post $post
* #return Response
*/
public function unBookmarkPost(Request $request,$id)
{
$unbook = Auth::guard('api')->user()->bookmarks()->detach($id);
return response()->json( $unbook);
}
There is the code for the BookmarkController
After defining the relationship in the User Model, I created a method to check if the post has been favorited in my Post model
public function bookmarked()
{
return (bool) Bookmark::where('user_id', Auth::guard('web')->id())
->where('job_id', $this->id)
->first();
}
There is the code for the Post Model. This is supposed to check if the post was bookmared.
So i also set up a vue component that takes in two props
<bookmark-icon :id="job.id" :bookmarked="job.bookmarked ? true : false "></bookmark-icon>
So my major problem now is i am using the bookmark-icon as a child component how would i call the bookmarked() method on the Vue instance, if it were blade it would have been
{{$job->bookmarked()}}
How do i get that with Vue??
You cannot access eloquent form in vuejs.
But You can use the relationship BEFORE you pass the data to vuejs.
In order to do that you have to eager load it
(read up on it on the docs if it is new to you, very useful stuff, especially when it comes to performance)
You can read this article "Importance of eager loading "
This is how you can do it, something like this code below:
public function load_display()
{
$job = Job::bookmarked()->get();
return response()->json($job );
}

Use Angular templating in content which is injected using innerHTML

I have an Angular (4) template which injects what I give it using [innerHTML], and this cannot be changed as it's an external package. So originally I had something like this:
public getMessages(): InterfaceName {
return {
emptyMessage: `<span>Some content!</span>`
}
}
I then passed this into the template of the external element:
<external-element [messages]="this.getMessages()"></external-element>
This worked perfectly. However, the product I am working on needs to support internationalisation, so the strings all need to come from a separate JSON file, and Angular's TranslateService is used to retrieve the strings and render them. So in the internationalisation file, I had an array of messages which would each be posted to the emptyMessage object above. So I had this:
public getMessages(): InterfaceName {
const messages = this.translate.instant('PATH.TO.JSON.STRINGS');
return {
emptyMessage: `
<div>
<span *ngFor="let message of messages;">{{ message }}</span>
</div>`
}
}
However, this just rendered {{ message }}, presumably due to introducing the possibility of an XSS attack, Angular sanitised the HTML. I also tried to use [innerHTML]="message" but this just showed up blank.
So how can I get the content from the i18n file and render it, after which the content is injected using innerHTML, of which I have no control?

Angular 2 + SignalR - Accessing Angular internals from external script

I'm using SignalR with an Angular2 app, where we want the SignalR client methods to call into the Angular app with data received from the server, and then have Angular redo the data-bindings. For example, within the Angular app I expose a global variable for our store, which has a collection on it.
E.g.
(TypeScript)
....
export class Store{
Customers : Customer[];
constructor(){
window["GlobalStore"] = this;
}
setCustomers (customers : Customer[]){
this.Customers = customers;
}
}
....
and in my client SignalR javascript I have a function:
$.connection.MyHub.client.receive = function(data){
//Call into the Angular app and set data, which is then rendered in views
//via data-binding
//data contains a json array of customers
window.GlobalStore.setCustomers(data);
}
This seems to work and set the data on the store, however, when the data is reset Angular does not seem to detect changes, and hence the UI is not refreshed.
It's not an issue with data-typing, as even passing a simple string/integer etc through to the store correctly sets the store property when I debug, however, the Angular framework doesn't seem to then trigger change detection and refresh the views.
Any ideas on how to either:
A) Manually trigger the angular databinding so it refreshes the view?
B) Call methods within the Angular 2 app from external using a different means?
Thanks
To manually run change detection:
Use ApplicationRef::tick() method.
Use NgZone::run() method to wrap you code which should be executed inside angular zone.
You can get them by using dependency injection or by bootstrapping your application using platform().application(bindings).bootstrap(Component):
import { platform } from 'angular2/angular2';
const app = platform().application([] /* - bindings */); // you can use `app.tick()`
const zone = app.zone; // you can use `zone.run`
app.bootstrap(Component);

In Vanilla JavaScript, how do I structure my app when having multiple Models/Views/Controllers?

I'm trying to get a practical grasp of MVC model implementation (not the conceptual understanding) in JavaScript.
As for the start, I thought it would be worth making an effort and try building a MVC app in plain JS. I've read dozens of articles and book chapters referring to MVC and its variations. Of course I googled lots of examples to see how it's done for real. The most understandable and with the proper meaning is in my opinion this one:
https://github.com/tastejs/todomvc/tree/master/examples/vanillajs
In the end, I was able to refactor my own app in the todomvc-vanillajs way.
However, there is one thing that still bothers me. All these apps and examples are very basic, so there is only one Model, View and Controller specified for the whole app.
What if I wanted to add more (equally complex) features to such app?
Should I add them one by one to my controller.js view.js and model.js files or whether should I stop developing spaghetti code and add new files instead, thus creating new models, controllers and views for each of the new feature individually?
It seems to me, that every feature should have its own view, controller and model, or at least, could have, depending on the subjective evaluation. But I'm not quite sure how such implementation should look at this situation in terms of code structure, namespacing etc.?
What if I want to imitate a scale by creating multiple views, models and controllers on every single functionality like e.g. handling an "add task to the list" or "delete the task" actions.
For the purpose of my dilemma, I've created my own MVC draft, which has two models, controllers and views. Whether such an approach would make sense? What happens when further developing my application, I quickly get to the point where I have dozens and more specific (coresponding) models, views and controllers.
Heres is the aforementioned fiddle.
;(function () {
'use strict';
/**
* #file ./App.js
*/
var App = {
Model : {},
Controller : {},
View : {}
};
console.log('start');
window.App = App;
})();
/* -------------Views-folder----------------------*/
/* -------------separate-file-----------------------*/
(function () {
'use strict';
/**
* #file Views/buildAdd.js
*/
var buildAdd = {
// render
// event
// pass the reference to event handler in Controller
};
App.View.buildAdd = buildAdd;
})(App);
/* -------------separate-file-----------------------*/
(function () {
'use strict';
/**
* #file Views/buildDelete.js
*/
var buildDelete = {
// render
// event
// pass the reference to event handler in Controller
};
App.View.buildDelete = buildDelete;
})(App);
/* -------------Controllers-folder----------------------*/
/* -------------separate-file-----------------------*/
(function () {
'use strict';
var addController = {
// handle the event and decide what the Model has to do
// handle the response from Model and tells the View how to update
};
App.Controller.addController = addController;
})(App);
/* -------------separate-file-----------------------*/
(function () {
'use strict';
var deleteController = {
// handle the event and decide what the Model has to do
// handle the response from Model and tells the View how to update
};
App.Controller.deleteController = deleteController;
})(App);
/* -------------Models-folder----------------------*/
/* -------------separate-file-----------------------*/
(function () {
'use strict';
var addModel = {
// send request
// get response
};
App.Model.addModel = addModel;
})(App);
/* -------------separate-file-----------------------*/
(function () {
'use strict';
var deleteModel = {
// send request
// get response
};
App.Model.deleteModel = deleteModel;
})(App);
/* -------------separate-file-----------------------*/
Thus, I found this question very similar to mine, but the provided answers are not entirely satisfactory, at least to me.
Check my implementation of so called Single Page Application framework. The whole thing is of 60 lines of code. It uses jQuery but can be implemented in VanilaJS.
Basic idea is simple - your app is just a collection of pages a.k.a. views
<section id="route1" src="content1.htm" />
<section id="route2" src="content2.htm" />
...
Sections id's define set of possible "routes"
SpAPP catches browser's navigate event and load requested view on the route.
And partial content1..N.htm files contain view markup, setup and controller functions.
Data model here is JS data received from server and stored in memory or in local storage.
As of MVC frameworks in general... You cannot bring joy to everyone and free of charge. That small SpAPP thing that can easily be understood and adjusted to particular project's needs is a way to go I think.
Looking at my experience in Ruby on Rails framework, I don't always need all three elements of MVC pattern. Sometimes you need a model for a database but it's only accessed internally, not by the client. Or sometimes you only need a generic helper class.
As a convention, the files are split, each one has its own controller, model and view, following a naming convention, maybe something like:
articles-view.html
articles-controller.js
articles-model.js
Views are split for each action in the controller:
articles-index.html
articles-show.html
articles-update.html
...
articles-controller.js
articles-model.js
Inside the controller, you will have the "actions", the functions for everything semantically related to an Article in a blog.
function ArticlesController() {
function index() { ... }
function create() { ... }
function edit() { ... }
...
function delete() { ... }
}
In models, you basically have the class / prototype itself, something that is built with the given data.
function Article() {
this.name = "";
this.author = "";
this.text = "";
this.dateCreated = "";
}
And finally, your views should have element with the same name used in the model.
If you have a basic CRUD system, for example, you can have just one controller and one model, but different views (one for listing all items, one for creating and editing, one for just one item, etc).
Taking examples from Rails and NodeJS, a way to write less code for the views is by using "partials". Common HTML structures can be saved on a file and imported into other HTML files as needed, such a form, the headers, the footer of a page and so on.
Example:
Instead of having a form on articles-create.html and another on articles-edit.html, you will have something like:
_articles-form.html <- this is your partial!
articles-create.html
articles-edit.html
"_articles-form.html" will be imported / appended into the create and edit pages.
Other common features can be consider as "Helpers". They are not a letter in "MVC", but often used. Like the Datepicker library, a simple validation function, a parser, etc. Something that can be used by everyone, not a specific feature of a class.
The project structure could be something like:
app/
app/controllers/
app/controllers/articles-controller.js
app/models/
app/models/articles-model.js
app/views/
app/views/articles/
app/views/articles/index.html
app/views/articles/create.html
app/views/articles/edit.html
app/views/articles/delete.html
app/views/articles/_form.html
Also, having a Manager functionality as you described above, will help you load all the data needed. Some function that maybe will read a json file, looking for the feature's name and parsing through the file's names, loading everything.
The manager would check if there is a model file, a controller file and a folder with N view files in it, containg the word "articles". The same would happen to "authors", "comments", "users" and so on.
I understand that you are proposing this question for study reasons and you took JS as a personal preference, so I´m not saying "don't try it" or something like that. But something to consider: the MVC pattern tackles applications that involves both client and server side. Unless your are developing on a full stack with NodeJS and MongoDB (or other similar technologies), HTML and Javascript are more on the View side of the application (or as helpers).
And if you are developing something like a library, you'll end up putting everything on a single file and minifying/uglifying it. Take JQuery as an example. Javascript developers often go with the Module pattern. They create an object, expose methods and variables that the other developer needs to know and that's it.
So, probably (but not for sure, you never know!), you won't see or work on many vanilla Javascript applications implementing MVC pattern.

JSF Best Practice: Custom Components and JavaScript

I am developing a JSF Custom Component, using the information I found on the following book Pro JSF and HTML5 by Apress.
So far, I successfully developed:
the java class to obtain the data to be rendered in the component
the java component class
the java renderer class
the taglib file
an example page to render the taglib
Everything is working fine, the component is successfully rendered.
Now I would like to add javascript events and behaviour to the rendered elements, more specifically, the purpose of my custom component is to render a menu on a web page, and I would like to ad a dropdown effects to the menu entry. I know how to code the whole thing, in JavaScript, what I don't know is:
What is the best practice to add javascript events and behaviour to the element rendered within a custom component?
Where should the JS files be placed? How do I bind the events to the elements? Is it done in the render class, or after, on the web pages?
Thanks, I'm willing to provide more specific information about my code, if required.
Java Component Class
Note: The CosmoMenu class is just a bean. It basically stores a menu tree (a label, an id and a set of children, if any).
package components;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import domain.CosmoMenu;
import javax.faces.component.FacesComponent;
import javax.faces.component.UIComponentBase;
#FacesComponent(CosmoMenuComponent.COMPONENT_TYPE)
public class CosmoMenuComponent extends UIComponentBase{
/** Component family of {#link CosmoMenuComponent}. */
public static final String COMPONENT_FAMILY = "CosmoMenu";
/** Component type of {#link CosmoMenuComponent}. */
public static final String COMPONENT_TYPE = "CosmoMenu";
#Override
public String getFamily(){
return CosmoMenuComponent.COMPONENT_FAMILY;
}
private CosmoMenu theMenu;
public CosmoMenu getMenu(){
Gson gson = new Gson();
JsonParser jsonParser = new JsonParser();
CosmoMenuAPI myApi = new CosmoMenuAPI();
String strMenu = myApi.getMenu();
JsonElement jEl = jsonParser.parse(strMenu);
theMenu = gson.fromJson(jEl, CosmoMenu.class);
return theMenu;
}
}
If you want your components to be reusable, I encourage you to pack everything in an independent jar. If using Servlet 3.0, you'll be able to easily access the web resources putting them in META-INF/resources. Provide the jar a faces-config.xml and you'll make it JSF annotation scannable:
components
\-(Your cource code)
META-INF
\-faces-config.xml
\-resources (This ends up in docroot)
\-resources
\-js (Here they go your js files)
\-comp (Here your composite components)
\-css (Here your css)
Later on, you'll have to take care of avoiding the specific ids in your composites, as JSF modifies them while rendering. Your best is to pass the current component reference to your JS functions:
<h:inputText styleClass="myInputStyle" onclick="showInputText(this)" />
Just refer to included CSS styles and JS functions.
Last but not least, be careful when including the jar as a web resource, if the file paths remain in conflict with the ones in your web app, they won't be included.
See also:
Exposing resources from jar files in web applications (Tomcat7)
How to reference JSF managed beans which are provided in a JAR file?
How can I know the id of a JSF component so I can use in Javascript
You can include into the facelets wich uses your component an external javascript file by adding the following code:
<script src="#{request.contextPath}/jspath/yourjs.js"></script>
Within the component when you generate the XHTML output give an Id to your menu entries e.g.
<h:outputText id="myid" value="#{bean.value}"/>
and in yourjs.js
$(document).ready(function() {
$("#myid").click(function(){
// dostuff
});
});

Categories

Resources