I want to make an editor of files. By the following code (JSBin), we list all the file names on the left hand, and their body on the right hand. I use ui-codemirror to style the body of the files.
However, when we click on the file names and switch from one to another, from time to time, we could see the quick flick from a textarea to a codemirror frame, which is not a good experience for an editor.
Does anyone have a solution to avoid the flick? Addtionally, is it a good direction to make an editor by angularJS and ui-codemirror?
<html ng-app="flapperNews">
<head>
<link rel="stylesheet" href="https://codemirror.net/lib/codemirror.css">
<script src="https://code.jquery.com/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.3.2/angular-ui-router.js"></script>
<script src="https://codemirror.net/lib/codemirror.js"></script>
<script src="https://codemirror.net/mode/xml/xml.js"></script>
<script src="https://codemirror.net/mode/htmlmixed/htmlmixed.js"></script>
<script src="https://codemirror.net/mode/javascript/javascript.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui/0.4.0/angular-ui.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.11.0/ui-bootstrap-tpls.js"></script>
<script>
var app = angular.module('flapperNews', ['ui', 'ui.router']);
app.config(['$stateProvider', function ($stateProvider) {
$stateProvider
.state('file', {
template: '<textarea ui-codemirror="editorOptionsHTML" ng-model="file.body"></textarea>',
controller: 'FileCtrl',
params: { name: null }
})
}]);
app.controller('MainCtrl', ['$scope', '$state', function ($scope, $state) {
$scope.files = [
{ name: "index.html", body: "<html><body>index.html</body></html>" },
{ name: "index.js", body: "the body of index.js" },
{ name: "test.html", body: "the body of test.html" }];
}]);
app.controller('FileCtrl', ['$scope', '$stateParams', function ($scope, $stateParams) {
$scope.file = $scope.files.find(function (file) { return file.name === $stateParams.name });
$scope.editorOptionsHTML = { mode: 'text/html', lineNumbers: true, matchBrackets: true };
}]);
</script>
</head>
<body ng-controller="MainCtrl">
<div class="row">
<div class="col-sm-3 col-md-3 col-xl-3 col-lg-3">
<div ng-repeat="file in files track by $index">
<a ui-sref="file({name: file.name})">{{file.name}}</a>
</div>
</div>
<div class="col-sm-9 col-md-9 col-xl-9 col-lg-9">
<ui-view></ui-view>
</div>
</div>
</body>
</html>
Every time you click on the link, it is creating new editor, which is an expense operation.
The best approach is to create one editor and load the content on every click.
so I removed the ui-router linking (ui-sref) and related controllers
<script>
var app = angular.module('flapperNews', ['ui', 'ui.router']);
app.controller('MainCtrl', ['$scope', '$state', function ($scope, $state) {
$scope.files = [
{ name: "index.html", body: "<html><body>index.html</body></html>" },
{ name: "index.js", body: "the body of index.js" },
{ name: "test.html", body: "the body of test.html" }];
$scope.editorOptionsHTML = { mode: 'text/html', lineNumbers: true, matchBrackets: true };
// for every click event it will load the content
$scope.go=function(file){
$scope.file=file;
}
}]);
and the body
<body ng-controller="MainCtrl">
<div class="row">
<div class="col-sm-3 col-md-3 col-xl-3 col-lg-3">
<div ng-repeat="file in files track by $index">
<a ng-click="go(file)">{{file.name}}</a>
</div>
</div>
<div class="col-sm-9 col-md-9 col-xl-9 col-lg-9">
<textarea ui-codemirror="editorOptionsHTML" ng-model="file.body"></textarea>
</div>
</div>
</body>
Example : JSBin
you could avoid the flick by adding hide class to textarea like the following code ( jsbin )
template: '<textarea class="hide" ui-codemirror="editorOptionsHTML" ng-model="file.body"></textarea>',
Related
I am using fullcalendar 5 and have created a custom view according to the documentaion
In may calendar configuration I have added this eventClick: (info) => this.displayDetail(info) it work great with the default views but can't figure out how to trigger the eventClick from my customview
How could I trigger it.
Customview configuration:
import { sliceEvents, createPlugin } from '#fullcalendar/core'
const CustomViewConfig = {
classNames: ['list-view'],
duration: {
month: 1.5
},
buttonText: 'Planning',
content (props, element) {
let html = '<div class="row">'
const events = sliceEvents(props, false)
for (const event of events) {
html += `
<div class="col-12 col-md-6 event color-${event.def.sourceId}">
<div class="row mb-4">
<div class="col-4">
<div class="col-date">
<span>${event.range.start.getDate()} ${event.range.start.toLocaleString('default', { month: 'long' })}</span>
<span>${event.range.end.getDate()} ${event.range.end.toLocaleString('default', { month: 'long' })}</span>
</div>
</div>
<div class="col-8">
<div class="col-content">
${event.def.title}
</div>
</div>
</div>
</div>
`
}
html += '</div>'
return { html: html }
}
}
export default createPlugin({
views: {
custom: CustomViewConfig
}
});
I am making an angularJS app where my goal is, when a user clicks a button inside one of the ng-repeat div, it should get focus by blurring all the other entries in of ng-repeat. I have created a minimal plunkr and described the problem with the image below.
I have this html
<ul ng-repeat="detail in details">
<li>
<div style="border-style:solid;"> {{detail.name}} </div>
</li>
</ul>
and the Empty Controller:
app.controller('MainCtrl', function ($scope) {
$scope.details =
[
{ "name": "Employees" },
{ "name": "Support" }
];
$scope.details.name =
[
{ "prof": "enginerr" },
{ "prof": "doctor" }
];
});
I have also added an image for demonstration
and created a plunkr for reference.
I am trying to achieve the bottom part of the image.
Thanks in advance.
Here's the sample I have created , please refer to it . Hopes this help you out. Thanks.
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.details = [
{ "name": "Employees" },
{ "name": "Support" }
];
$scope.details.name = [
{ "prof": "enginerr" },
{ "prof": "doctor" }
];
$scope.isActive=false;
$scope.clickMe = function(index){
$scope.currentIndex=index;
$scope.isActive=!$scope.isActive;
}
});
/* Put your css in here */
.notActive {
pointer-events: none;
cursor: not-allowed;
opacity: 0.3;
}
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>
document.write('<base href="' + document.location + '" />');
</script>
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js#1.0.x" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js" data-semver="1.0.8"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<ul ng-repeat="detail in details">
<li style="border-style:solid;" ng-class="{'notActive':isActive && currentIndex!=$index}">
<div > {{detail.name}} </div>
<button ng-click="clickMe($index)">Click me</button>
</li>
</ul>
</body>
</html>
The line {{> Template.dynamic template=content }} makes my page not load. It actually crashes my browser sometimes. I had it working for a while but something happened and now it does not work anymore.
{{> Template.dynamic template='navBar' }} works so my packages should be ok.
Meteor: 1.4
Packages: kadira:flow-router, kadira:blaze-layout
imports/ui/layouts/mainLayout.html:
<template name="mainLayout">
<header>
<div class="container">
{{> navBar }}
</div>
</header>
<body>
<div class="container">
{{> Template.dynamic template=content }} <!-- not working -->
</div>
</body>
<footer>
<div class="container">
<h3>Footer</h3>
</div>
</footer>
</template>
imports/ui/layouts/mainLayout.js:
import { Template } from 'meteor/templating';
import './mainLayout.html';
import '../components/navBar.html';
import '../pages/settings.html';
imports/startup/client/routes.js:
import { FlowRouter } from 'meteor/kadira:flow-router';
import { BlazeLayout } from 'meteor/kadira:blaze-layout';
import '../../ui/layouts/mainLayout.js';
import '../../ui/pages/settings.js';
FlowRouter.route('/', {
action() {
BlazeLayout.render('mainLayout', { content: 'mainLayout' });
},
});
FlowRouter.route('/settings', {
action() {
BlazeLayout.render('mainLayout', { content: 'settings' });
},
});
imports/ui/pages/settings.html:
<template name="settings">
<div class="container">
<h1>This is the settings page</h1>
</div>
</template>
This route:
FlowRouter.route('/', {
action() {
BlazeLayout.render('mainLayout', { content: 'mainLayout' });
},
});
is not going to work because you are inserting the mainLayout component into itself - the nested content helper is the issue. Instead, you should be rendering a different component into content:
BlazeLayout.render('mainLayout', { content: 'home' }); // or whatever component should be at "/"
I am trying to use masonry in my application. Following is my component template.
<template>
<div>
<section class="section">
<div class="container">
<div class="row team">
<div class="col-md-4 col-sm-6 member" v-for="team in teamMembers">
<div class="team__item">
<div class="team__info">
<h4>{{team.name}}</h4>
<small>{{team.title}}</small>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
</template>
<script src="https://unpkg.com/masonry-layout#4.1.1/dist/masonry.pkgd.min.js"></script>
<script>
export default {
data() {
return {
teamMembers: []
}
},
mounted() {
this.getTeamMembers();
},
methods : {
getTeamMembers : function() {
this.$http.get('teamMembers').then(response =>{
// console.log(response);
if(response.data.status=200) {
this.teamMembers = response.data.teamMembers;
this.$nextTick(function() {
var $container = $('.team');
$container.masonry({
columnWidth: '.member',
itemSelector: '.member'
});
})
}
})
}
}
}
</script>
I get the following error whenever the view is getting rendered.
TypeError: $container.masonry is not a function
Can you please let me know what I am doing wrong here ?
You can get vue component DOM element by this.$el. So you can do the following:
$(this.$el.querySelector('.team')).masonry({
columnWidth: '.member',
itemSelector: '.member'
});
But remember this is valid as long as your component is not a Fragment Instance i.e. it has a single root HTML tag.
You many need to put following script line in index.html, so that it loads properly.
<script src="https://unpkg.com/masonry-layout#4.1.1/dist/masonry.pkgd.min.js"></script>
I have a firebase structure like this:
"workouts" : {
"-KBJiXAHZV2B8sj9-FNk" : {
"exercise_templates" : {
"-KEsVT-ukSHMNevLFCa1" : true,
"-KEslP747OVTdIYrNmCv" : true,
"-KEslUBaSsmTOiVgV_h_" : true,
"-KFpJyXrZwY_aPiDGGvw" : true
},
"name" : "ICF A"
}
}
"exercise_templates" : {
"-KEsVT-ukSHMNevLFCa1" : {
"name" : "Overhead Press",
"reps" : "5",
"sets" : "5",
"workouts" : {
"-KBJiXAHZV2B8sj9-FNk" : true,
"-KEsU4Q0irvgh33I20JF" : true
}
},
I'm trying to loop through all exercise_templates that belong to a workout:
<template is="dom-repeat" items="[[workouts]]" as="workout">
<paper-card heading="[[workout.name]]">
<div class="card-content">
[[workout.__firebaseKey__]]
<template is="dom-repeat" items="[[workout.exercise_templates]]" as="template" handle-as="json">
{{template}}
</template>
</div>
<div class="card-actions">
<paper-button>Some action</paper-button>
</div>
</paper-card>
</template>
But I get:
[dom-repeat::dom-repeat]: expected array for `items`, found Object {-KEsVT-ukSHMNevLFCa1: true, -KEslP747OVTdIYrNmCv: true, -KEslUBaSsmTOiVgV_h_: true, -KFpJyXrZwY_aPiDGGvw: true}
How would I go about referencing an exercise_template by iterating through the exercise_templates in workouts?
Custom element
<dom-module id="my-workout">
<template>
<template is="dom-bind">
<style>
:host {
display: block;
}
span {
#apply(--paper-font-body1);
}
</style>
<firebase-collection
limit-to-first="10"
location="https://blazing-inferno-5257.firebaseio.com/workouts"
data="{{workouts}}" keys="{{keys}}"></firebase-collection>
<template is="dom-repeat" items="[[workouts]]" as="workout">
<paper-card heading="[[workout.name]]">
<div class="card-content">
<template is="dom-repeat" items="[[_computeExerciseTemplates(workout)]]">
<li>{{item}}</li>
</template>
</div>
<div class="card-actions">
<paper-button>Do workout</paper-button>
</div>
</paper-card>
</template>
</template>
</template>
<script>
(function() {
'use strict';
Polymer({
is: 'my-workout',
_computeExerciseTemplates: function(workout) {
return Object.keys(workout.exercise_templates);
},
ready: function() {
}
});
})();
</script>
</dom-module>
Assuming exercise_templates cannot be changed into a simple array (or that it's undesirable), you could use a computed binding for exercise_templates to get its keys:
<template is="dom-repeat" items="[[_computeExerciseTemplates(workout)]]">
<li>{{item}}</li>
</template>
where _computeExerciseTemplates is defined as:
<script>
Polymer({
...
_computeExerciseTemplates: function(workout) {
return Object.keys(workout.exercise_templates);
}
});
</script>
<head>
<base href="https://polygit.org/polymer+:master/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link rel="import" href="polymer/polymer.html">
</head>
<body>
<x-foo></x-foo>
<dom-module id="x-foo">
<template>
<template is="dom-repeat" items="[[workouts]]" as="workout">
<h2>{{workout.name}}</h2>
<ul>
<template is="dom-repeat" items="[[_computeExerciseTemplates(workout)]]">
<li>{{item}}</li>
</template>
</ul>
</template>
</template>
<script>
Polymer({
is: 'x-foo',
properties: {
workouts: {
type: Array,
value: function() {
return [{
//"-KBJiXAHZV2B8sj9-FNk" : {
"exercise_templates": {
"-KEsVT-ukSHMNevLFCa1": true,
"-KEslP747OVTdIYrNmCv": true,
"-KEslUBaSsmTOiVgV_h_": true,
"-KFpJyXrZwY_aPiDGGvw": true
},
"name": "ICF A"
//}
}]
}
}
},
_computeExerciseTemplates: function(workout) {
return Object.keys(workout.exercise_templates);
}
});
</script>
</dom-module>
</body>
jsbin