In the project I'm working on there some components structured like this:
;(function () {
'use strict'
angular
.module('a')
.component('comp', {
templateUrl: function (Config) {
return Config.path + '/a/a.template.html'
}
...
And every component had its own template file, but there were little to no difference beetween them so I created one template file to be used in all of them, but when I changed a.template.html to b.template.html only in some of the components the changes took place, and when I inspected the unchanged elements the HTML that was being used was from a.template.html. Why only some of the components being changed? (Also the components have the same hiarchy and are also really alike)
I figured it out, turns out that my browser was storing the HTML in the cache, so what worked was to just clear the browser cache.
Related
I'm using Redux in a vanilla JS project. I have a bunch of small modular UI files and controllers and such. In those UI files I might have code like:
const ExampleForm = function (StoreInstance) {
return $('<form />', {
submit: () => {
StoreInstance.dispatch({
type: 'EXAMPLE_DISPATCH',
post: {
message: $TextareaComponent.val()
}
})
return false
}
})
}
The issue is I have a lot of simple view files like this and many of them are nested and I'm finding it to be ugly and error prone to have the store passed as a param to everything.
For example, I trimmed it for brevity but the form component has form element components such as a textarea. Currently I see two options of managing the Store:
Setting it to window when creating it in my entry file (index.js) and then just accessing Store globally. This seems the nicest, although not "best practice" and makes unit testing and server side rendering a bit harder.
Passing it to every component tediously. This is my example above. This I'd consider as "best practice" but it's pretty annoying to do for every file you make almost.
I'm wondering if there's any alternatives or tricks to passing the store instance. I'm leaning towards just making it global.
You could use the constructor pattern and create every view as new ConnectedView(). The ConnectedView would have a memoized instance of the store (this.store within the view), so it doesn't need to be global.
If I have a template in a component that references non-existant components, angular 1.6 seems perfectly happy to render it as nothing at all. For example I have a route currently that looks like:
when('/something',{
title: 'Something',
template: "<mycomponent></mycomponent>",
})
If I forget to register mycomponent on my application, this route renders nothing. Is there some mode I can use in angular that will cause a harder error in a case like that? Or at least print something to the console when it occurs?
To be perfectly clear, I have this issue with both top level components referenced by the router, as well as other child components that those reference recursively.
No, there is no option for that. By the way "non rendered" components are a benefit IMO, because you could override this slot later.
A short example:
when('/something',{
title: 'Something',
template: "<slot><mycomponent></mycomponent></slot>",
})
assume you want to override the ui-part of mycomponent, just define a component for "slot"
There was a routeProvider.otherwise before. Not sure if it’s still supported. I’m on a phone so limited. Let me know how it goes.
UI Router supports components for routes, this means that it is capable of triggering an error if a component doesn't exist.
AngularJS currently doesn't offer component router. This means that route template is compiled as any other template with $compile, and unknown selectors are just ignored.
It is possible to patch ngRoute ngView directive to additionally check if a route that is expected to route to a component actually has it compiled.
// the whole list can be retrieved from commonly available sources
var htmlTags = ['p', 'div', ...];
app.directive('ngView', function () {
return function($scope, $element, $attrs) {
if (!DEBUG_MODE)
return;
if ($element.children().length !== 1)
return;
var routeComponent = angular.element($element.children()[0]);
var routeComponentTagName = routeComponent.prop('tagName').toLowerCase();
if (htmlTags.indexOf(routeComponentTagName) >= 0)
return;
var routeComponentName = $attrs.$normalize(routeComponentTagName);
if (!routeComponent.controller(routeComponentName)) {
console.warn(routeComponentTagName + ' element is non-standard yet not a component');
}
}
});
AngularJS already has $normalize() which is primarily intended for attributes and strips some specific prefixes, but as long as the components names don't have x or data prefix, it can work as generic kebab to camel case transformer.
There may be other ways to detect if a component was compiled on child element. The code above will trigger false negative if there already is parent routeComponentName component, because controller() travels up the hierarchy.
And the proper way to handle this problem is to provide test coverage for the application. Router-related cases should likely be handled in integration or e2e tests.
I'm working on a large app with legacy code. I've run into this issue twice now and am realizing there must be a better solution than what I've done to solve it. The issue is as follows.
There are 3 separate pages where I need to add very similar Vue functionality. However, these pages have significantly different HTML/Blade templates. Therefore, it's like I have to pass in separate HTML/Blade templates to the component in addition to component props.
I can kind of accomplish this using Vue inline-templates, which takes care of the significantly different HTML/Blade template problem.
However, the remaining issue is that I have 3 .js Vue components, one for each page. This would be fine, except the Vue code in each file is very similar.
It's also possible that at some point I will need to add more unique Vue code to each component, and would like to keep that possibility open.
What I would like to do is find a way to reuse the Vue code that is very similar in each component.
I have tried thinking of a way to nest the same child component within each of these 3 separate components, but I don't see how that would be possible due to the differences in the HTML/Blade in each file.
Any suggestions would be most appreciated, as I feel like I'm duplicating too much Vue code!
Thanks to user thanksd for providing the solution in the comments above. Mixins indeed were the way to go for me. That way, instead of this:
Vue.component('first-component', {
template: // something unique
methods : {
functionNumber1: function () {
// do something
},
});
Vue.component('second-component', {
template: // something totally different
methods : {
functionNumber1: function () {
// do same something
},
}
});
I can essentially do this:
const myMixin = {
methods : {
functionNumber1: function () {
// do same something
},
}
Vue.component('first-component', {
template: // something unique
mixins: ['myMixin']
});
Vue.component('second-component', {
template: // something totally different
mixins: ['myMixin']
});
So, I'm trying to setup Aurelia in my Angular 1 web application so I can slowly upgrade. I need to do that since the application is too big and migrating everything at once would be impossible.
So, in my Aurelia folder I created a component folder with two components (aurelia-component.js and another-component.js with their views aurelia-component.html and another-component.html), I won't put the javascript as they are just two classes with one property, the html for both is the same, the only thing that changes is the text property value so I can differentiate them:
<template>
<div>${text}</div>
</template>
My entry point main.js looks like this:
export function configure(aurelia) {
aurelia.use
.basicConfiguration()
.developmentLogging()
.globalResources('components/aurelia-component')
.globalResources('components/another-component');
//window.aurelia = aurelia;
aurelia.start()
.then(a => {
window.aurelia = a;
});
}
As you can see, this puts Aurelia in the window object so I can access it from my Angular app, I'll improve this later.
In my angular app I have this directive:
'use strict';
function AureliaContainer() {
function Link($scope, element, attrs) {
window.aurelia.enhance(element[0]);
}
//
return {
restrict: 'A',
link: Link
};
}
module.exports = AureliaContainer;
I set this up in my app root with:
app.directive('aureliaContainer', require('./directives/aurelia.container'));
And in my Angular View I have these divs with my directive that calls the enhance function from Aurelia:
<div aurelia-container>
<aurelia-component></aurelia-component>
</div>
<div aurelia-container>
<another-component></another-component>
</div>
The reason I have two aurelia-container in the html is that I know I'll have to have more than one when I'm migrating the application.
And this works fine, both components load normally in the screen.
The problem is when I try to call another component from within one of those components.
What I did was, I created a new component called test-component.js with its view test-component.html. The html for this is just:
<template>
<h1>Header</h1>
</template>
And then, from the aurelia-component.html I called it using:
<template>
<require from="./test-component"></require>
<div>${text}</div>
<test-component></test-component>
</template>
Now, when I load the page, the test-component actually loads but the <div>${text}</div part of aurelia-component doesn't and I get this error in the console:
Uncaught (in promise) TypeError: Cannot read property 'behaviorInstructions' of undefined
I really don't understand why this error is happening, I should be able to load a custom element from within another one normally, shouldn't I. Or is there a limitation when you use enhance?
I also tried to use setRoot in both divs with no success, just one of them is loaded.
Maybe there's a better approach for this?
Again, I can't migrate my entire application at once, it's just no feasible.
Thanks in advance for the help.
First off, I know nothing about progressive enhancement in Aurelia. And cannot comment about its suitability for your scenario.
But I am wondering if maybe you missed some Au dependencies (like binding or templating?)
http://aurelia.io/hub.html#/doc/article/aurelia/framework/latest/app-configuration-and-startup/8
aurelia.use
.defaultBindingLanguage()
.defaultResources()
.developmentLogging()
.globalResources('resources/my-component');
That might explain why it fails when you want it to render a template?
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.