How can I validate files before uploading in angular 4 and above?
i want file type and file size validation in angular 4 and above.
Screenshot of my issue
for each and every file I am getting correct file size and type except .msg file. How to get
file type as application/vnd.ms-outlook
application/octet-stream
for outlook files. Please help me out.
Your question is a bit (lot) vague. I assume you mean, how do you get the File object from an input in Angular. Dead simple. The same way you would with vanilla(ish) JS.
In your component, create a function to read your file:
readFile(fileEvent: any) {
const file = fileEvent.target.files[0];
console.log('size', file.size);
console.log('type', file.type);
}
And apply it to the (change) event on your input in your template:
<input type="file" (change)="readFile($event)">
You can do whatever you like with the file after that. The sample function just gets the size and type, as per your question.
Stackblitz Example: https://stackblitz.com/edit/angular-vpvotz
As a (slight) aside, rather than using any as the fileEvent type, you can define an interface to give you type hinting.
interface HTMLInputEvent extends Event {
target: HTMLInputElement & EventTarget;
}
While you're at it, also add the File type too. So your function becomes:
readFile(fileEvent: HTMLInputEvent) {
const file: File = fileEvent.target.files[0];
console.log('size', file.size);
console.log('type', file.type);
}
But, you don't have to. Although any types are not recommended.
Related
My application uses CKEditor 5 to allow users to edit rich text data. These texts support some application-specific custom elements (Web Components), and I want to extend CKEditor with custom plugins that support inserting such custom elements. I seem to be almost there, but I'm having some difficulties getting these custom elements into and out of the CKEditor instance properly.
Current plugin implementations
I mainly followed the Implementing an inline widget tutorial from the CKEditor 5 documentation. As an example, I would like to support a custom element like <product-info product-id="123"></product-info>, which in CKEditor should be rendered as a simple <span> with a specific class for some styling.
In my editing plugin, I first define the extension to the schema:
const schema = this.editor.model.schema;
schema.register('product-info', {
allowWhere: '$text',
isInline: true,
isObject: true,
allowAttributes: [ 'product-id' ]
});
I then define the upcast and downcast converters, closely sticking to the tutorial code:
const conversion = this.editor.conversion;
conversion.for('upcast').elementToElement({
view: {
name: 'span',
classes: [ 'product-info' ]
},
model: (viewElement, { writer: modelWriter }) => {
const id = viewElement.getChild(0).data.slice(1, -1);
return modelWriter.createElement('product-info', { 'product-id': id });
}
});
conversion.for('editingDowncast').elementToElement({
model: 'product-info',
view: (modelItem, { writer: viewWriter }) => {
const widgetElement = createProductInfoView(modelItem, viewWriter);
return toWidget(widgetElement, viewWriter);
}
});
conversion.for('dataDowncast').elementToElement({
model: 'product-info',
view: (modelItem, { writer: viewWriter }) => createProductInfoView(modelItem, viewWriter)
});
function createProductInfoView(modelItem, viewWriter) {
const id = modelItem.getAttribute('product-id');
const productInfoView = viewWriter.createContainerElement(
'span',
{ class: 'product-info' },
{ isAllowedInsideAttributeElement: true }
);
viewWriter.insert(
viewWriter.createPositionAt(productInfoView, 0),
viewWriter.createText(id)
);
return productInfoView;
}
Expected behavior
The idea behind all this is that I need to support the custom <product-info> elements stored in user data in the backend. CKEditor, which is used by users to edit that data, should load these custom elements and transform them into a styled <span> for display purposes while editing. These should be treated as inline widgets since they should only be able to be inserted, moved, copied, pasted, deleted as a whole unit. A CKEditor plugin should allow the user to create new such elements to be inserted into the text, which will then also be <span>s in the editing view, but <product-info>s in the model, which should also be written back to the backend database.
In other words, I expected this to ensure a direct mapping between element <product-info product-id="123"></product-info> in the model, and <span class="product-info">123</span> in the view, to support inserting and moving of <product-info> elements by the user.
Actual result
In short, I seem to be unable to get CKEditor to load data containing <product-info> elements, and unable to retrieve the model representation of these custom elements for backend storage. All operations to insert data to CKEditor from source, or to retrieve CKEditor data for sending to the backend, seem to operate on the view.
For example, if I preload CKEditor contents either by setting the inner content of the element that is replaced with the editor instance, or inserting it like this:
const viewFragment = editor.data.processor.toView(someHtml);
const modelFragment = editor.data.toModel(viewFragment);
editor.model.insertContent(modelFragment);
I see the following behavior (verified using CKEditor Inspector):
When inserting the custom element, i.e. <product-info product-id="123"></product-info>, the element is stripped. It's not present in either the model nor the view.
When inserting the view representation, i.e. <span class="product-info">123</span> I get the representation that I want, i.e. that same markup in CKEditor's view, and the <product-info product-id="123"></product-info> tag in the model.
This is exactly the opposite of what I want! In my backend, I don't want to store the view representation that I created for editing purposes, I want to store the actual custom element. Additionally:
My UI plugin to insert new product info elements, uses a command that does the following:
execute({ value }) {
this.editor.model.change( writer => {
const productInfo = writer.createElement('product-info', {
'product-id': value
});
this.editor.model.insertContent(productInfo);
writer.setSelection(productInfo, 'on');
});
}
which also works as I want it to, i.e. it generates the product-info tag for the model and the span for the view. But, of course, when loading an entire source text when initialising the editor with data from the backend, I can't use this createElement method.
Conversely, in order to retrieve the data from CKEditor for saving, my application uses this.editor.getData(). There, these proper pairs of <product-info> model elements and <span> view elements get read out in their view representation, instead of their model representation – not what I want for storing this data back!
The question
My question is: what do I need to change to be able to load the data into CKEditor, and get it back out of the CKEditor, using the custom element, rather than the transformed element I want to show only for editing purposes? Put differently: how can I make sure the content I insert into CKEditor is treated as the model representation, and how do I read out the model representation from my application?
I'm confused about this because if the model representation is something that is only supposed to be used internally by CKEditor, and not being able to be set or retrieved from outside – then what is the purpose of defining the schema and these transformations in the first place? It will only ever be visible to CKEditor, or someone loading up the CKEditor Inspector, but of no use to the application actually integrating the editor.
Sidenote: an alternative approach
For a different approach, I tried to forgo the transformation to <span>s entirely, and just use the custom element <product-info>, unchanged, in both the model and the view, by using the General HTML Support functionality. This worked fine, since this time no transformation was needed, all I had to do was to set the schema in order for CKEditor to accept and pass through the custom elements.
The reason I can't go with this approach is that in my application, these custom components are handled using Angular Elements, so they will actually be Angular components. The DOM manipulation seems to interfere with CKEditor, the elements are no longer treated as widgets, and there are all manner of bugs and side effects that come with it. Elements show up fine in CKEditor at first, but things start falling apart when trying to select or move them. Hence my realisation that I probably need to create a custom representation for them in the CKEditor view, so they're not handled by Angular and preventing these issues.
I am using Google Apps Script to call an external API to post both text and an image to a contact in an external system. I have posted the text fine, many times, no problems. I have not worked with sending or even using images in Apps Script before, so I am unsure of how to send the image as a file. I've done quite a bit of research on Stack Overflow and elsewhere, but have not found the answer to this yet.
The API documentation for the external system says that it needs the following:
contactId - Type: String
Message:
text - Type: String... Description: Message text (Media or Text is required).
upload - Type: File... Description: Message image (Media or Text is required). Media must be smaller than 1.5mb. Use a jpg, jpeg, png, or gif.
The "upload", type "File" (a jpg picture/image) is what I cannot figure out how to grab, format, and send. I currently have the image in Google Drive, have shared it for anyone to access via its URL, and it is well under 1.5MB.
Here is most of my test code (marked as JS, but really Google Apps Script), with the identifying info changed, with several different ways I have tried it. At this point, I am just banging my head against the wall! Any help is greatly appreciated!!! Thank you!
function TestAPI() {
var apiKey2 = '9xxxxx-xxxx2-xxxxx-bxxx-3xxxxxxa'; //API Key for the external system
var url4 = 'https://www.externalsystem.com/api/v1/[contactID]/send';
var pic = DriveApp.getFileById("1yyyyyy_Nyyyyxxxxxx-_xxxxxxx_xyyyy_"); // I Tried this
// var pic = driveService.files().get('1yyyyyy_Nyyyyxxxxxx-_xxxxxxx_xyyyy_'); //And tried this
// var pic = DriveApp.getFileByID('1yyyyyy_Nyyyyxxxxxx-_xxxxxxx_xyyyy_').getAs(Family.JPG); //And this
// var pic = { "image" : { "source": {"imageUri": "https://drive.google.com/file/d/1yyyyyy_Nyyyyxxxxxx-_xxxxxxx_xyyyy_" } } }; //And this
// var pic = { file : DriveApp.getFileById("1yyyyyy_Nyyyyxxxxxx-_xxxxxxx_xyyyy_") }; //And this
var formData = {
'contactID': '[contactID]',
'text': "Text here to send to external system through API", // This works fine every time!
'upload': pic // Tried this
// 'upload': DriveApp.getFileByID("1yyyyyy_Nyyyyxxxxxx-_xxxxxxx_xyyyy_").getBlob() // And tried this
// 'upload': { "image" : { "source": {"imageUri": "https://drive.google.com/file/d/1yyyyyy_Nyyyyxxxxxx-_xxxxxxx_xyyyy_" } } } // And this
};
var options4 = {
"headers":{"x-api-key":apiKey2},
'method' : 'post',
'payload': formData
};
var response4 = UrlFetchApp.fetch(url4, options4);
}
Once again, everything is working fine (text, etc.) except for the image (the "upload") not coming through. I am pretty sure it is because I don't know how to "package" the image from Google Drive through the UrlFetchApp call to the API.
The official document says that Message text (Media or Text is required) and Message image (Media or Text is required). From this, please try to test as following modification.
Modified request body:
var formData = {
upload: DriveApp.getFileById("###").getBlob()
};
I thought that from the official document, when both 'upload' and 'text' are used, only 'text' might be used.
And also, from your tested result, it was found that the request body is required to be sent as the form data.
Reference:
Contacts - Send Message To Contact
I am adding files to my dropzone as instructed in documentation. Then later I would like to check dropzone if it has any added mock files. Is there a way I could achieve this? Dropzone.files seems to be empty. It contains only the files uploaded in current session.
I am adding files like this:
var mockFile = { name: "Image1", size: fileSize };
myDropzone.emit("addedfile", mockFile);
myDropzone.emit("thumbnail", mockFile, "images/img.jpg");
myDropzone.files.push(mockFile);
You must use myDropzone.files.push(mockFile), when adding you mock files.
var currentDialog = CKEDITOR.dialog.getCurrent();
currentDialog._.editor.insertHtml("<customTag myAttr='var'></customTag>");
Throws an error, TypeError: Cannot read property 'isBlock' of undefined
If I try .insertHtml("<span>hello</span>") it works just fine.
How can I change ckeditor to allow me to specify my own custom html tags via .insertHtml()? I'd love to just change it to be something like <span class='custom'... or something like that, but I'm having to deal with legacy CMS articles. Using latest ckeditor. Thanks.
You need to modify CKEDITOR.dtd object so editor will know this tag and correctly parse HTML and process DOM:
CKEDITOR.dtd.customtag = { em:1 }; // List of tag names it can contain.
CKEDITOR.dtd.$block.customtag = 1; // Choose $block or $inline.
CKEDITOR.dtd.body.customtag = 1; // Body may contain customtag.
You need to allow for this tag and its styles/attrs/classes in Advanced Content Filter:
editor.filter.allow( 'customtag[myattr]', 'myfeature' );
Unfortunately, due to some caching, in certain situations you cannot modify DTD object after CKEditor is loaded - you need to modify it when it is created. So to do that:
Clone the CKEditor repository or CKEditor presets repository.
Modify core/dtd.js code.
And build your minified package following instructions in README.md - the only requirements are Java (sorry - Google Closure Compiler :P) and Bash.
PS. That error should not be thrown when unknown element is inserted, so I reported http://dev.ckeditor.com/ticket/10339 and to solve this inconvenience http://dev.ckeditor.com/ticket/10340.
I worked around this issue with a combination of createFromHtml() and insertElement()
CKEDITOR.replace('summary', { ... });
var editor = CKEDITOR.instances.summary;
editor.on('key', function(ev) {
if (ev.data.keyCode == 9) { // TAB
var tabHtml = '<span style="white-space:pre"> </span>';
var tabElement = CKEDITOR.dom.element.createFromHtml(tabHtml, editor.document);
editor.insertElement(tabElement);
}
}
I am trying to implement CKEditor 4 into an ASP NET website that I am working on, but I cannot figure out how I would save the edited material from the inline editor I know how to do it with the the old version, but I just don't understand the process for this.
I have looked in the forums... There is not v4 forum.
I looked in for the documentation.... Couldn't find it.
I have a feeling that this is a simple task, but I just don't know how.
You can get your data with CKEDITOR.instances.editor1.getData(). Then you can send it via AJAX or store it as a value of some input field. To do this periodically, follow this method:
CKEDITOR.disableAutoInline = true;
var editor = CKEDITOR.inline( 'editable' );
var savedData, newData;
function saveEditorData() {
setTimeout( function() {
newData = editor.getData();
if ( newData !== savedData ) {
savedData = newData;
// Send it with jQuery Ajax
$.ajax({
url: 'yourUrl',
data: savedData
});
// Or store it anywhere...
// ...
// ...
}
saveEditorData();
}, 500 );
};
// Start observing the data.
saveEditorData();
You can also observe the submit event and update some (hidden) form field with your data.
Have fun!
Are you trying to get it with AJAX or send with a form? The value of for example the top right inline editor area with Lorem Ipsum can be gotten like in the older version with simply
CKEDITOR.instances.editor1.getData().
In the XHTML output example they have a simple form that seems to work and I believe that using an (static) inline editor is just the same.
If you transform elements into editors inline dynamically, I would try to bind to the submit event and before submitting loop through all CKEDITOR.instances, get their data into hidden from fields. As for the hidden field naming or identifying which hidden field corresponds to which dynamic editor you'll have to figure out yourself :)